Как я могу сделать это с помощью echo
?
perl -E 'say "=" x 100'
Как я могу сделать это с помощью echo
?
perl -E 'say "=" x 100'
Вы можете использовать:
printf '=%.0s' {1..100}
Как это работает:
Bash расширяет {1..100}, поэтому команда становится:
printf '=%.0s' 1 2 3 4 ... 100
Я установил формат printf в =%.0s
, что означает, что он всегда будет печатать один =
независимо от того, какой аргумент он задает. Поэтому он печатает 100 =
s.
Нет простого способа. Но, например:
seq -s= 100|tr -d '[:digit:]'
Или, может быть, стандартный способ:
printf %100s |tr " " "="
Там также есть tput rep
, но что касается моих терминалов под рукой (xterm и linux), они, похоже, не поддерживают его:)
Там более одного способа сделать это.
Использование цикла:
Расширение скобки можно использовать с целыми литералами:
for i in {1..100}; do echo -n =; done
C-подобный цикл позволяет использовать переменные:
start=1
end=100
for ((i=$start; i<=$end; i++)); do echo -n =; done
Использование printf
builtin:
printf '=%.0s' {1..100}
Указание точности здесь обрезает строку, чтобы она соответствовала указанной ширине (0
). Поскольку printf
повторно использует строку формата для использования всех аргументов, это просто печатает "="
100 раз.
Использование head
(printf
и т.д.) и tr
:
head -c 100 < /dev/zero | tr '\0' '='
printf %100s | tr " " "="
Совет для шляпы @gniourf_gniourf для его ввода.
Примечание. Этот ответ не отвечает на исходный вопрос, но дополняет существующие, полезные ответы, сравнивая производительность.
Решения сравниваются только с точки зрения скорости выполнения - требования к памяти не принимаются во внимание (они различаются между решениями и могут иметь значение с большим количеством повторений).
Резюме:
${var// /=}
), поскольку он является слишком медленным.Ниже приведены timings, принятые на iMac в конце 2012 года с процессором Intel Core i5 с тактовой частотой 3,2 ГГц и Fusion Drive с OSX 10.10.4 и Bash 3.2.57, и это в среднем 1000 прогонов.
Записи:
M
... потенциально многосимвольное решениеS
... односимвольное решениеP
... POSIX-совместимое решение[M, P] printf %.s= [dogbane]: 0.0002
[M ] printf + bash global substr. replacement [Tim]: 0.0005
[M ] echo -n - brace expansion loop [eugene y]: 0.0007
[M ] echo -n - arithmetic loop [Eliah Kagan]: 0.0013
[M ] seq -f [Sam Salisbury]: 0.0016
[M ] jot -b [Stefan Ludwig]: 0.0016
[M ] awk - $(count+1)="=" [Steven Penny (variant)]: 0.0019
[M, P] awk - while loop [Steven Penny]: 0.0019
[S ] printf + tr [user332325]: 0.0021
[S ] head + tr [eugene y]: 0.0021
[S, P] dd + tr [mklement0]: 0.0021
[M ] printf + sed [user332325 (comment)]: 0.0021
[M ] mawk - $(count+1)="=" [Steven Penny (variant)]: 0.0025
[M, P] mawk - while loop [Steven Penny]: 0.0026
[M ] gawk - $(count+1)="=" [Steven Penny (variant)]: 0.0028
[M, P] gawk - while loop [Steven Penny]: 0.0028
[M ] yes + head + tr [Digital Trauma]: 0.0029
[M ] Perl [sid_com]: 0.0059
awk
и perl
.[M ] Perl [sid_com]: 0.0067
[M ] mawk - $(count+1)="=" [Steven Penny (variant)]: 0.0254
[M ] gawk - $(count+1)="=" [Steven Penny (variant)]: 0.0599
[S ] head + tr [eugene y]: 0.1143
[S, P] dd + tr [mklement0]: 0.1144
[S ] printf + tr [user332325]: 0.1164
[M, P] mawk - while loop [Steven Penny]: 0.1434
[M ] seq -f [Sam Salisbury]: 0.1452
[M ] jot -b [Stefan Ludwig]: 0.1690
[M ] printf + sed [user332325 (comment)]: 0.1735
[M ] yes + head + tr [Digital Trauma]: 0.1883
[M, P] gawk - while loop [Steven Penny]: 0.2493
[M ] awk - $(count+1)="=" [Steven Penny (variant)]: 0.2614
[M, P] awk - while loop [Steven Penny]: 0.3211
[M, P] printf %.s= [dogbane]: 2.4565
[M ] echo -n - brace expansion loop [eugene y]: 7.5877
[M ] echo -n - arithmetic loop [Eliah Kagan]: 13.5426
[M ] printf + bash global substr. replacement [Tim]: n/a
${foo// /=}
) необъяснимо мучительно медленна с большими строками и выведена из работы (заняла около 50 минут (!) в Bash 4.3.30 и даже дольше в Bash 3.2.57 - я никогда не ждал, пока он закончится).(( i= 0; ... ))
) медленнее, чем расширенные с помощью скобок ({1..n}
), хотя арифметические циклы более эффективны с точки зрения памяти.awk
относится к BSD awk
(также найденному на OSX) - он заметно медленнее, чем gawk
(GNU Awk) и особенно mawk
.Здесь Bash script (testrepeat
), который создал выше.
Он принимает 2 аргумента:
Иными словами: приведенные выше тайминги были получены с помощью testrepeat 100 1000
и testrepeat 1000000 1000
#!/usr/bin/env bash
title() { printf '%s:\t' "$1"; }
TIMEFORMAT=$'%6Rs'
# The number of repetitions of the input chars. to produce
COUNT_REPETITIONS=${1?Arguments: <charRepeatCount> [<testRunCount>]}
# The number of test runs to perform to derive the average timing from.
COUNT_RUNS=${2:-1}
# Discard the (stdout) output generated by default.
# If you want to check the results, replace '/dev/null' on the following
# line with a prefix path to which a running index starting with 1 will
# be appended for each test run; e.g., outFilePrefix='outfile', which
# will produce outfile1, outfile2, ...
outFilePrefix=/dev/null
{
outFile=$outFilePrefix
ndx=0
title '[M, P] printf %.s= [dogbane]'
[[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
# !! In order to use brace expansion with a variable, we must use `eval`.
eval "
time for (( n = 0; n < COUNT_RUNS; n++ )); do
printf '%.s=' {1..$COUNT_REPETITIONS} >"$outFile"
done"
title '[M ] echo -n - arithmetic loop [Eliah Kagan]'
[[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
time for (( n = 0; n < COUNT_RUNS; n++ )); do
for ((i=0; i<COUNT_REPETITIONS; ++i)); do echo -n =; done >"$outFile"
done
title '[M ] echo -n - brace expansion loop [eugene y]'
[[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
# !! In order to use brace expansion with a variable, we must use `eval`.
eval "
time for (( n = 0; n < COUNT_RUNS; n++ )); do
for i in {1..$COUNT_REPETITIONS}; do echo -n =; done >"$outFile"
done
"
title '[M ] printf + sed [user332325 (comment)]'
[[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
time for (( n = 0; n < COUNT_RUNS; n++ )); do
printf "%${COUNT_REPETITIONS}s" | sed 's/ /=/g' >"$outFile"
done
title '[S ] printf + tr [user332325]'
[[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
time for (( n = 0; n < COUNT_RUNS; n++ )); do
printf "%${COUNT_REPETITIONS}s" | tr ' ' '=' >"$outFile"
done
title '[S ] head + tr [eugene y]'
[[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
time for (( n = 0; n < COUNT_RUNS; n++ )); do
head -c $COUNT_REPETITIONS < /dev/zero | tr '\0' '=' >"$outFile"
done
title '[M ] seq -f [Sam Salisbury]'
[[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
time for (( n = 0; n < COUNT_RUNS; n++ )); do
seq -f '=' -s '' $COUNT_REPETITIONS >"$outFile"
done
title '[M ] jot -b [Stefan Ludwig]'
[[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
time for (( n = 0; n < COUNT_RUNS; n++ )); do
jot -s '' -b '=' $COUNT_REPETITIONS >"$outFile"
done
title '[M ] yes + head + tr [Digital Trauma]'
[[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
time for (( n = 0; n < COUNT_RUNS; n++ )); do
yes = | head -$COUNT_REPETITIONS | tr -d '\n' >"$outFile"
done
title '[M ] Perl [sid_com]'
[[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
time for (( n = 0; n < COUNT_RUNS; n++ )); do
perl -e "print \"=\" x $COUNT_REPETITIONS" >"$outFile"
done
title '[S, P] dd + tr [mklement0]'
[[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
time for (( n = 0; n < COUNT_RUNS; n++ )); do
dd if=/dev/zero bs=$COUNT_REPETITIONS count=1 2>/dev/null | tr '\0' "=" >"$outFile"
done
# !! On OSX, awk is BSD awk, and mawk and gawk were installed later.
# !! On Linux systems, awk may refer to either mawk or gawk.
for awkBin in awk mawk gawk; do
if [[ -x $(command -v $awkBin) ]]; then
title "[M ] $awkBin"' - $(count+1)="=" [Steven Penny (variant)]'
[[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
time for (( n = 0; n < COUNT_RUNS; n++ )); do
$awkBin -v count=$COUNT_REPETITIONS 'BEGIN { OFS="="; $(count+1)=""; print }' >"$outFile"
done
title "[M, P] $awkBin"' - while loop [Steven Penny]'
[[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
time for (( n = 0; n < COUNT_RUNS; n++ )); do
$awkBin -v count=$COUNT_REPETITIONS 'BEGIN { while (i++ < count) printf "=" }' >"$outFile"
done
fi
done
title '[M ] printf + bash global substr. replacement [Tim]'
[[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
# !! In Bash 4.3.30 a single run with repeat count of 1 million took almost
# !! 50 *minutes*(!) to complete; n Bash 3.2.57 it seemingly even slower -
# !! didn't wait for it to finish.
# !! Thus, this test is skipped for counts that are likely to be much slower
# !! than the other tests.
skip=0
[[ $BASH_VERSINFO -le 3 && COUNT_REPETITIONS -gt 1000 ]] && skip=1
[[ $BASH_VERSINFO -eq 4 && COUNT_REPETITIONS -gt 10000 ]] && skip=1
if (( skip )); then
echo 'n/a' >&2
else
time for (( n = 0; n < COUNT_RUNS; n++ )); do
{ printf -v t "%${COUNT_REPETITIONS}s" '='; printf %s "${t// /=}"; } >"$outFile"
done
fi
} 2>&1 |
sort -t$'\t' -k2,2n |
awk -F $'\t' -v count=$COUNT_RUNS '{
printf "%s\t", $1;
if ($2 ~ "^n/a") { print $2 } else { printf "%.4f\n", $2 / count }}' |
column -s$'\t' -t
Я только что нашел очень простой способ сделать это с помощью seq:
UPDATE: это работает на BSD seq
, который поставляется с OS X. YMMV с другими версиями
seq -f "#" -s '' 10
Будет напечатан "#" 10 раз, например:
##########
-f "#"
устанавливает строку формата, чтобы игнорировать числа и просто печатать #
для каждого из них.-s ''
устанавливает разделитель в пустую строку, чтобы удалить символы новой строки, которые seq вставляет между каждым числом-f
и -s
кажутся важными.EDIT: здесь это удобно...
repeat () {
seq -f $1 -s '' $2; echo
}
Что вы можете назвать так...
repeat "#" 10
ПРИМЕЧАНИЕ. Если вы повторяете #
, то кавычки важны!
Вот два интересных способа:
[email protected]:~$ yes = | head -10 | paste -s -d '' - ========== [email protected]:~$ yes = | head -10 | tr -d "\n" [email protected]:~$
Обратите внимание, что эти два метода несколько отличаются. Метод paste
заканчивается в новой строке. Метод tr
не работает.
Нет простого способа. Избегайте циклов, используя printf
и замену.
str=$(printf "%40s")
echo ${str// /rep}
# echoes "rep" 40 times.
#!/usr/bin/awk -f
BEGIN {
OFS = "="
NF = 100
print
}
Или же
#!/usr/bin/awk -f
BEGIN {
while (z++ < 100) printf "="
}
Если вы хотите, чтобы соответствие и согласованность POSIX для разных реализаций echo
и printf
и/или оболочек, отличных от bash
:
seq(){ n=$1; while [ $n -le $2 ]; do echo $n; n=$((n+1)); done ;} # If you don't have it.
echo $(for each in $(seq 1 100); do printf "="; done)
... будет выдавать тот же результат, что и perl -E 'say "=" x 100'
примерно везде.
Чистый Bash способ без eval
, без подоболочек, без внешних инструментов, без расширений (например, вы можете иметь число для повторения в переменной):
Если вам задана переменная n
, которая расширяется до (неотрицательного) числа и переменной pattern
, например,
$ n=5
$ pattern=hello
$ printf -v output '%*s' "$n"
$ output=${output// /$pattern}
$ echo "$output"
hellohellohellohellohello
Вы можете сделать функцию с этим:
repeat() {
# $1=number of patterns to repeat
# $2=pattern
# $3=output variable name
local tmp
printf -v tmp '%*s' "$1"
printf -v "$3" '%s' "${tmp// /$2}"
}
С этим набором:
$ repeat 5 hello output
$ echo "$output"
hellohellohellohellohello
Для этого небольшого трюка мы используем printf
довольно много:
-v varname
: вместо печати на стандартный вывод printf
будет помещать содержимое форматированной строки в переменную varname
.printf
будет использовать аргумент для печати соответствующего количества пробелов. Например, printf '%*s' 42
будет печатать 42 пробела.${var// /$pattern}
будет расширяться до расширения var
со всеми замененными пространствами расширение $pattern
.Вы также можете избавиться от переменной tmp
в функции repeat
, используя косвенное расширение:
repeat() {
# $1=number of patterns to repeat
# $2=pattern
# $3=output variable name
printf -v "$3" '%*s' "$1"
printf -v "$3" '%s' "${!3// /$2}"
}
Я предполагаю, что первоначальная цель вопроса состояла в том, чтобы сделать это только с помощью встроенных команд оболочки. Таким образом, циклы for
и printf
будут законными, а rep
, perl
, а также jot
ниже - нет. Тем не менее, следующая команда
jot -s "/" -b "\\" $((COLUMNS/2))
например, печатает всю ширину окна \/\/\/\/\/\/\/\/\/\/\/\/
Как говорили другие, в bash расширение брекета предшествует расширение параметра, поэтому диапазоны {m,n}
могут содержать только литералы. seq
и jot
обеспечивают чистые решения но не полностью переносимы из одной системы в другую, даже если вы используете одну и ту же оболочку для каждого. (Хотя seq
становится все более доступным, например в FreeBSD 9.3 и выше. eval
, и другие формы косвенности всегда работают, но несколько неэлегантные.
К счастью, bash поддерживает C-стиль для циклов (только с арифметическими выражениями). Итак, вот краткий "чистый bash" способ:
repecho() { for ((i=0; i<$1; ++i)); do echo -n "$2"; done; echo; }
Это принимает количество повторений в качестве первого аргумента и повторяющуюся строку (которая может быть одним символом, как в описании проблемы) в качестве второго аргумента. repecho 7 b
выводит bbbbbbb
(завершается символом новой строки).
Деннис Уильямсон дал принципиально это решение четыре года назад в своем превосходном ответе до Создание строки повторяющихся символов в оболочке script. Мое функциональное тело немного отличается от кода:
Поскольку основное внимание здесь уделяется повторению одного символа, а оболочка bash, вероятно, безопасно использовать echo
вместо printf
. И я прочитал описание проблемы в этом вопросе как выражение предпочтения печатать с echo
. Вышеуказанное определение функции работает в bash и ksh93. Хотя printf
более портативен (и обычно должен использоваться для такого рода вещей), синтаксис echo
, возможно, более читабельен.
Некоторые оболочки echo
встроены в интерпретацию -
сами по себе как опцию - хотя обычный смысл -
, чтобы использовать stdin для ввода, для t28 не имеет смысла. zsh делает это. И определенно существует echo
, которые не распознают -n
, поскольку он не является стандартным. (Многие оболочки в стиле Бурна вообще не принимают C-стиль для циклов, поэтому их поведение echo
не нужно учитывать.)
Здесь задача состоит в том, чтобы напечатать последовательность; там, он должен был назначить его переменной.
Если $n
- желаемое количество повторений, и вам не нужно его повторно использовать, и вы хотите что-то еще более короткое:
while ((n--)); do echo -n "$s"; done; echo
n
должен быть переменной - этот способ не работает с позиционными параметрами. $s
- текст, который необходимо повторить.
Вопрос был о том, как это сделать с помощью echo
:
echo -e ''$_{1..100}'\b='
Это будет сделано точно так же, как perl -E 'say "=" x 100'
но только с echo
.
В bash 3.0 или выше
for i in {1..100};do echo -n =;done
Python вездесущ и работает везде одинаково.
python -c "import sys; print('*' * int(sys.argv[1]))" "=" 100
Символ и число передаются как отдельные параметры.
for i in {1..100}
do
echo -n '='
done
echo
repeat() {
# $1=number of patterns to repeat
# $2=pattern
printf -v "TEMP" '%*s' "$1"
echo ${TEMP// /$2}
}
Если вы хотите повторить символ n раз, когда n имеет значение VARIABLE, количество раз, в зависимости от длины строки, которую вы можете сделать:
#!/bin/bash
vari='AB'
n=$(expr 10 - length $vari)
echo 'vari equals.............................: '$vari
echo 'Up to 10 positions I must fill with.....: '$n' equal signs'
echo $vari$(perl -E 'say "=" x '$n)
Отображается:
vari equals.............................: AB
Up to 10 positions I must fill with.....: 8 equal signs
AB========
Это более длинная версия того, что Элия Каган поддерживала:
while [ $(( i-- )) -gt 0 ]; do echo -n " "; done
Конечно, вы можете использовать printf для этого, но не очень мне нравится:
printf "%$(( i*2 ))s"
Эта версия совместима с Dash:
until [ $(( i=i-1 )) -lt 0 ]; do echo -n " "; done
где я - начальное число.
Как я мог сделать это с эхо?
Вы можете сделать это с помощью echo
если за echo
следует sed
:
echo | sed -r ':a s/^(.*)$/=\1/; /^={100}$/q; ba'
На самом деле, это echo
там не нужно.
Проще всего использовать эту строку в bash:
seq 10 | xargs -n 1 | xargs -I {} echo -n ===\>;echo
Более элегантная альтернатива предлагаемому решению Python может быть:
python -c 'print "="*(1000)'
Другой вариант - использовать GNU seq и удалить все числа и новые строки, которые он генерирует:
seq -f'#%.0f' 100 | tr -d '\n0123456789'
Эта команда печатает символ #
100 раз.
function repeatString()
{
local -r string="${1}"
local -r numberToRepeat="${2}"
if [[ "${string}" != '' && "${numberToRepeat}" =~ ^[1-9][0-9]*$ ]]
then
local -r result="$(printf "%${numberToRepeat}s")"
echo -e "${result// /${string}}"
fi
}
Пробные прогоны
$ repeatString 'a1' 10
a1a1a1a1a1a1a1a1a1a1
$ repeatString 'a1' 0
$ repeatString '' 10
Ссылка на библиотеку по адресу: https://github.com/gdbtek/linux-cookbooks/blob/master/libraries/util.bash
Проще всего использовать эту однострочную строку в csh/tcsh:
printf "%50s\n" '' | tr '[:blank:]' '[=]'
Мой ответ немного сложнее и, вероятно, не идеален, но для тех, кто хочет выводить большие числа, я смог сделать около 10 миллионов за 3 секунды.
repeatString(){
# argument 1: The string to print
# argument 2: The number of times to print
stringToPrint=$1
length=$2
# Find the largest integer value of x in 2^x=(number of times to repeat) using logarithms
power='echo "l(${length})/l(2)" | bc -l'
power='echo "scale=0; ${power}/1" | bc'
# Get the difference between the length and 2^x
diff='echo "${length} - 2^${power}" | bc'
# Double the string length to the power of x
for i in 'seq "${power}"'; do
stringToPrint="${stringToPrint}${stringToPrint}"
done
#Since we know that the string is now at least bigger than half the total, grab however many more we need and add it to the string.
stringToPrint="${stringToPrint}${stringToPrint:0:${diff}}"
echo ${stringToPrint}
}
Большинство существующих решений зависят от поддержки синтаксиса {1..10}
оболочки, которая специфична для bash
и zsh
и не работает в tcsh
или OpenBSD ksh
и в большинстве -bash sh
.
Следующее должно работать на OS X и всех системах * BSD в любой оболочке; фактически его можно использовать для создания целой матрицы различных типов декоративного пространства:
$ printf '=%.0s' 'jot 64' | fold -16
================
================
================
================$
К сожалению, мы не получаем завершающий перевод строки; который может быть исправлен дополнительным printf '\n'
после сгиба:
$ printf "=%.0s" 'jot 64' | fold -16 ; printf "\n"
================
================
================
================
$
Ссылки: