Як я міг це зробити echo
?
perl -E 'say "=" x 100'
ruby -e 'puts "=" * 100'
абоpython -c 'print "=" * 100'
printf
для seq
)svrb=`printf '%.sv' $(seq $vrb)`
Як я міг це зробити echo
?
perl -E 'say "=" x 100'
ruby -e 'puts "=" * 100'
абоpython -c 'print "=" * 100'
printf
для seq
)svrb=`printf '%.sv' $(seq $vrb)`
Відповіді:
Ви можете використовувати:
printf '=%.0s' {1..100}
Як це працює:
Bash розширюється {1..100}, так що команда стає:
printf '=%.0s' 1 2 3 4 ... 100
Я встановив формат printf, =%.0s
що означає, що він завжди буде друкувати єдиний =
незалежно від того, який аргумент він наводиться. Тому він друкує 100 =
с.
repl = 100
, наприклад ( eval
хитрість потрібна, на жаль, для основи розширення repl() { printf "$1"'%.s' $(eval "echo {1.."$(($2))"}"); }
seq
замість цього , наприклад $(seq 1 $limit)
.
$s%.0s
щоб %.0s$s
інакше тире спричинило printf
помилку.
printf
: він продовжує застосовувати рядок формату, поки не залишиться аргументів. Я припускав, що обробляє рядок формату лише один раз!
Непростий спосіб. Але, наприклад:
seq -s= 100|tr -d '[:digit:]'
А може бути стандартним способом:
printf %100s |tr " " "="
Також є tput rep
, але що стосується моїх терміналів під рукою (xterm та linux), схоже, вони не підтримують це :)
=
символів.
printf
tr
є єдиним рішенням , так як POSIX seq
, yes
а {1..3}
НЕ POSIX.
printf %100s | sed 's/ /abc/g'
- виводить 'abcabcabc ...'
tr
). Ви також можете поширити це на щось подібне printf "%${COLUMNS}s\n" | tr " " "="
.
wc
. Єдиний висновок, який я можу зробити з цього, - це " seq
не слід використовувати".
Підказка капелюха до @ gniourf_gniourf для його введення.
Примітка. Ця відповідь не відповідає на початкове запитання, але доповнює існуючі корисні відповіді, порівнюючи ефективність .
Рішення порівнюються лише з точки зору швидкості виконання - вимоги до пам’яті не враховуються (вони різняться в різних рішеннях і можуть мати значення при великій кількості повторень).
Підсумок:
${var// /=}
), оскільки це дуже повільно.Нижче наведено таймінги на iMac наприкінці 2012 року з процесорним процесором Intel Core i5 3,2 ГГц та Fusion Drive, що працює під керуванням OSX 10.10.4 та bash 3.2.57.
Записи:
M
... потенційно мульти -character рішення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// /=}
) Bash незбагненно повільна з великими рядками, і вона була виведена з роботи (зайняла близько 50 хвилин (!) В Bash 4.3.30, і ще довше в Bash 3.2.57 - я ніколи не чекав на це закінчити).(( i= 0; ... ))
) повільніші, ніж розширені дужки ( {1..n}
), хоча арифметичні петлі є більш ефективними в пам'яті.awk
відноситься до BSD awk
(як це також зустрічається на OSX) - він помітно повільніше, ніж gawk
(GNU Awk) і особливо mawk
.Ось сценарій Bash ( 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's 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
In order to use brace expansion with a variable, we must use `eval`
👍
Існує більше ніж один спосіб зробити це.
Використання циклу:
Розширення дужок можна використовувати з цілими буквами:
for i in {1..100}; do echo -n =; done
С-подібний цикл дозволяє використовувати змінні:
start=1
end=100
for ((i=$start; i<=$end; i++)); do echo -n =; done
Використання printf
вбудованого:
printf '=%.0s' {1..100}
Вказавши точність, тут обрізається рядок відповідно до заданої ширини ( 0
). Оскільки printf
повторно використовується рядок формату для споживання всіх аргументів, він просто друкується "="
100 разів.
Використання head
( printf
тощо) та tr
:
head -c 100 < /dev/zero | tr '\0' '='
printf %100s | tr " " "="
head
/ tr
рішення, яке добре працює навіть при високих підрахунках повторень (невеликий застереження: head -c
не сумісний з POSIX, але BSD та GNU head
реалізують це); в той час як інші два рішення будуть повільними в цьому випадку, вони також мають перевагу в роботі з багатознаковими рядками.
yes
і head
- корисно , якщо ви хочете певну кількість нових рядків: yes "" | head -n 100
. tr
може змусити його друкувати будь-який символ:yes "" | head -n 100 | tr "\n" "="; echo
dd if=/dev/zero count=1 bs=100000000 | tr '\0' '=' >/dev/null
значно повільніше, ніж head -c100000000 < /dev/zero | tr '\0' '=' >/dev/null
версія. Звичайно, вам потрібно використовувати розмір блоку 100 М +, щоб обґрунтовано виміряти різницю в часі. 100M байтів займають 1,7 с та 1 с із показаними двома відповідними версіями. Я зняв tr і просто скинув його /dev/null
і отримав 0,287 s для head
версії та 0,675 s за dd
версію на мільярд байтів.
dd if=/dev/zero count=1 bs=100000000 | tr '\0' '=' >/dev/null
=> 0,21332 s, 469 MB/s
; Для: dd if=/dev/zero count=100 bs=1000000| tr '\0' '=' >/dev/null
=> 0,161579 s, 619 MB/s
;
Щойно я знайшов серйозно простий спосіб зробити це за допомогою seq:
ОНОВЛЕННЯ: Це працює на BSD, seq
який постачається з OS X. YMMV з іншими версіями
seq -f "#" -s '' 10
Буде надруковано "#" 10 разів, як це:
##########
-f "#"
встановлює форматний рядок ігнорувати числа та просто друкувати #
для кожного.-s ''
встановлює роздільник на порожній рядок, щоб видалити нові рядки, які послідовно вставляє між кожним числом-f
і -s
здаються важливими.EDIT: Ось це зручна функція ...
repeat () {
seq -f $1 -s '' $2; echo
}
Якого ви можете назвати так ...
repeat "#" 10
ПРИМІТКА: Якщо ви повторюєте, #
то цитати важливі!
seq: format ‘#’ has no % directive
. seq
є для чисел, а не для рядків. Дивіться gnu.org/software/coreutils/manual/html_node/seq-invocation.html
seq
йде розумно переорієнтований тут дублюючі рядки : рядок формату передається -f
- зазвичай використовується для форматування числа генерується - містить тільки рядок повторити тут , так що висновок містить копії тільки той рядок. На жаль, GNU seq
наполягає на присутності формату чисел в рядку формату, який є помилкою , яку ви бачите.
"$1"
(подвійні лапки), щоб ви також могли передавати такі символи, як '*'
рядки та вбудовані пробіли. Нарешті, якщо ви хочете мати можливість користуватися %
, вам доведеться подвоїти його (інакше seq
ви вважаєте, що це частина специфікації формату, наприклад %f
); використовуючи "${1//%/%%}"
б подбати про це. Оскільки (як ви вже згадували) ви використовуєте BSD seq
, це працюватиме на BSD-подібних ОС загалом (наприклад, FreeBSD) - навпаки, це не буде працювати в Linux , де використовується GNU seq
.
Ось два цікавих способи:
ubuntu @ ubuntu: ~ $ yes = | голова -10 | вставити -s -d '' - ========== ubuntu @ ubuntu: ~ $ yes = | голова -10 | tr -d "\ n" ========== ubuntu @ ubuntu: ~ $
Зверніть увагу, що ці два тонко різні - paste
метод закінчується в новому рядку. tr
Метод не робить.
paste
необґрунтовно вимагає -d '\0'
ввести порожній роздільник, а не вдається -d ''
- -d '\0'
повинен працювати з усіма POSIX-сумісними paste
реалізаціями і справді працює і з GNU paste
.
yes | mapfile -n 100 -C 'printf = \#' -c 1
time yes = | head -500 | paste -s -d '\0' -; time yes | mapfile -n 500 -C 'printf = \#' -c 1
. Що ще важливіше: якщо ви все- printf
таки використовуєте , ви можете також скористатися більш простим та ефективним підходом із прийнятої відповіді:printf '%.s=' $(seq 500)
Немає простого способу. Уникайте циклів використання printf
та заміни.
str=$(printf "%40s")
echo ${str// /rep}
# echoes "rep" 40 times.
repl = 100
, наприклад, (не видає трейлінг \n
):repl() { local ts=$(printf "%${2}s"); printf %s "${ts// /$1}"; }
Якщо ви хочете 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'
скрізь.
seq
це не утиліта POSIX (хоча системи BSD та Linux мають її реалізацію) - ви можете робити арифметику оболонки POSIX while
замість циклу, як у відповіді @ Xennex81 (з printf "="
, як ви правильно вважаєте, а не echo -n
).
cal
є POSIX. seq
не. У будь-якому разі, замість того, щоб переписувати відповідь циклом на час (як ви говорите, це вже є в інших відповідях), я додам функцію RYO. Більш освічений таким чином ;-).
Питання полягало у тому, як це зробити echo
:
echo -e ''$_{1..100}'\b='
Це зробить точно так само, як perl -E 'say "=" x 100'
тільки з echo
лише.
Чистий спосіб 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}"
}
bash
операції з заміни глобальних рядків у контексті розширення параметрів ( ${var//old/new}
) особливо повільні: болісно повільні в bash 3.2.57
і повільні в bash 4.3.30
, принаймні на моїй системі OSX 10.10.3 на машині Intel Core i5 3,2 ГГц: кількість 1 000, все відбувається повільно ( 3.2.57
) / швидко ( 4.3.30
): 0,1 / 0,004 секунди. Зростання кількості до 10000 приносить вражаюче різні цифри: repeat 10000 = var
займає приблизно 80 секунд (!) В баші 3.2.57
і приблизно 0,3 секунди в баші 4.3.30
(набагато швидше, ніж на 3.2.57
, але все ж повільно).
#!/usr/bin/awk -f
BEGIN {
OFS = "="
NF = 100
print
}
Або
#!/usr/bin/awk -f
BEGIN {
while (z++ < 100) printf "="
}
awk 'BEGIN { while (c++ < 100) printf "=" }'
. Загорнута в параметризрвані функції оболонки (Invoke , як repeat 100 =
, наприклад): repeat() { awk -v count="$1" -v txt=".$2" 'BEGIN { txt=substr(txt, 2); while (i++ < count) printf txt }'; }
. ( .
substr
awk
=
NF = 100
Рішення дуже розумний (хоча , щоб отримати 100 =
, ви повинні використовувати NF = 101
). Застережень є те, що він виходить з ладу BSD awk
(але це дуже швидко з gawk
і навіть швидше mawk
), і що POSIX обговорюється ні не призначили до NF
, ні використання полів у BEGIN
блоках. Ви можете змусити його працювати і в BSD awk
, маючи невелику настройку: awk 'BEGIN { OFS = "="; $101=""; print }'
(але цікаво, що в BSD awk
це не швидше рішення циклу). В якості вирішення параметризрвані оболонки: repeat() { awk -v count="$1" -v txt=".$2" 'BEGIN { OFS=substr(txt, 2); $(count+1)=""; print }'; }
.
original-awk
ім'я під Linux старішого awk, схожого на awk BSD, яке також було повідомлено про збій, якщо ви хочете спробувати це. Зауважте, що збої - це зазвичай перший крок до пошуку помилкової помилки. Ця відповідь настільки пропагує небезпечний код.
original-awk
нестандартна і не рекомендується
awk NF=100 OFS='=' <<< ""
(з використанням bash
і gawk
)
Я здогадуюсь, що початковою метою цього питання було зробити це лише за допомогою вбудованих команд оболонки. Так for
петля і printf
s будуть законними, в той час як rep
, perl
і також jot
нижче не буде. Все-таки наступна команда
jot -s "/" -b "\\" $((COLUMNS/2))
наприклад, друкує вікно по всій лінії вікна \/\/\/\/\/\/\/\/\/\/\/\/
jot -s '' -b '=' 100
. Проблема полягає в тому , що в той час як BSD-подібних платформах, включаючи OSX, приходять з jot
, дистрибутиви Linux не .
apt install athena-jot
було б передбачено jot
.
Як вже говорили інші, розширення в bash brace передує розширенню параметрів , тому діапазони можуть містити лише літерали. і забезпечити чисті рішення, але вони не є повністю портативними з однієї системи в іншу, навіть якщо ви використовуєте однакову оболонку для кожної. (Хоча це все більше доступно; наприклад, у FreeBSD 9.3 і вище .) Та інші форми непрямості завжди працюють, але дещо неелегантні.{m,n}
seq
jot
seq
eval
На щастя, bash підтримує C-стиль для циклів (лише з арифметичними виразами). Тож ось стислий "чистий баш" спосіб:
repecho() { for ((i=0; i<$1; ++i)); do echo -n "$2"; done; echo; }
Це сприймає кількість повторів як перший аргумент, а рядок, яку потрібно повторити (що може бути одним символом, як в описі проблеми), як другий аргумент. repecho 7 b
виводи bbbbbbb
(закінчується новим рядком).
Денніс Вільямсон дав по суті це рішення чотири роки тому в його прекрасному відповідь на створення рядка символів, що повторюються в сценарії оболонки . Моє функціональне тіло дещо відрізняється від коду, який там є:
Оскільки в центрі уваги є повторення одного символу, а оболонка - це удар, його, мабуть, безпечно використовувати echo
замість printf
. І я читаю опис проблеми в цьому питанні як вираження переваги для друку echo
. Вищеописане визначення функції працює у bash та ksh93 . Хоча він printf
є більш портативним (і зазвичай його слід використовувати для подібних речей), echo
синтаксис, можливо, є більш читабельним.
Деякі echo
вбудовані оболонки інтерпретують -
самі собою як варіант - навіть незважаючи на те, що звичайний сенс -
використовувати stdin для введення даних, є безглуздим echo
. zsh робить це. І напевно існують такі echo
, які не розпізнають -n
, як це не стандартно . (Багато оболонок у стилі Борна взагалі не приймають шлейф у стилі С, тому їх echo
поведінку не слід враховувати.)
Тут завдання - надрукувати послідовність; там , це було призначити його змінної.
Якщо $n
потрібна кількість повторень, і вам не доведеться використовувати її повторно, і вам потрібно щось ще коротше:
while ((n--)); do echo -n "$s"; done; echo
n
повинна бути змінною - цей спосіб не працює з позиційними параметрами. $s
це текст, який потрібно повторити.
printf "%100s" | tr ' ' '='
є оптимальним.
zsh
і до речі. Підхід "Ехо-в-циклі" добре працює для менших підрахунків повторів, але для великих є альтернативи, сумісні з POSIX, засновані на утилітах , про що свідчить коментар @ Slomojo.
(while ((n--)); do echo -n "$s"; done; echo)
echo
вбудований модуль, який підтримує -n
. Дух того, що ви говорите, абсолютно правильний. printf
майже завжди слід віддавати перевагу echo
, принаймні, у неінтерактивному використанні. Але я не вважаю, що якимось чином недоречним чи оманливим було давати echo
відповідь на запитання, яке задало питання, і яке дало достатньо інформації, щоб знати, що це буде працювати . Зауважте також, що POSIX не гарантує підтримку ((n--))
(без $
).
Python є всюдисущим і працює скрізь однаково.
python -c "import sys; print('*' * int(sys.argv[1]))" "=" 100
Символ та кількість передаються як окремі параметри.
python -c "import sys; print(sys.argv[1] * int(sys.argv[2]))" "=" 100
Ще одне значення повторити довільну рядок n разів:
Плюси:
Мінуси:
yes
команда Gnu Core Utils .#!/usr/bin/sh
to_repeat='='
repeat_count=80
yes "$to_repeat" | tr -d '\n' | head -c "$repeat_count"
З терміналом ANSI та символами US-ASCII для повторення. Можна використовувати послідовність аварійної послідовності ANSI CSI. Це найшвидший спосіб повторити персонаж.
#!/usr/bin/env bash
char='='
repeat_count=80
printf '%c\e[%db' "$char" "$repeat_count"
Або статично:
Роздрукуйте рядок у 80 разів =
:
printf '=\e[80b\n'
Обмеження:
repeat_char
послідовність ANI CSI.repeat_char
послідовність ANSI CSI на повторний символ.Ось що я використовую для друку рядків символів на екрані в Linux (на основі ширини терміналу / екрана)
printf '=%.0s' $(seq 1 $(tput cols))
Пояснення:
Надрукуйте знак рівності стільки разів, скільки заданої послідовності:
printf '=%.0s' #sequence
Використовуйте вихід команди (це функція bash під назвою Command Substitution):
$(example_command)
Наведіть послідовність, я використав від 1 до 20 як приклад. У заключній команді використовується команда tput замість 20:
seq 1 20
Укажіть кількість стовпців, які зараз використовуються в терміналі:
tput cols
for i in {1..100}
do
echo -n '='
done
echo
Найпростішим є використання цього одного вкладиша в csh / tcsh:
printf "%50s\n" '' | tr '[:blank:]' '[=]'
У випадку, якщо ви хочете повторити символ 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========
length
не буде працювати expr
, ви, мабуть, мали на увазі n=$(expr 10 - ${#vari})
; Однак, це простіше і ефективніше використовувати арифметичне розширення в Bash: n=$(( 10 - ${#vari} ))
. Крім того, в основі вашої відповіді лежить той самий підхід Perl, який ОП шукає альтернативу Баша .
Це довша версія того, що підтримував Елія Каган:
while [ $(( i-- )) -gt 0 ]; do echo -n " "; done
Звичайно, для цього можна використовувати і printf, але не дуже мені подобається:
printf "%$(( i*2 ))s"
Ця версія сумісна з тире:
until [ $(( i=i-1 )) -lt 0 ]; do echo -n " "; done
при цьому я є початковим числом.
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
Моя відповідь трохи складніша і, мабуть, не ідеальна, але для тих, хто прагне вивести велику кількість, я зміг зробити близько 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}
}
Найпростішим є використання цього однолінійного вкладиша в bash:
seq 10 | xargs -n 1 | xargs -I {} echo -n ===\>;echo
Більшість існуючих рішень залежать від {1..10}
підтримки синтаксису оболонки, яка є bash
- і zsh
- специфічною, і не працює в tcsh
або OpenBSD ksh
та в більшості, що не є bash sh
.
У ОС X і всіх * BSD-системах у будь-якій оболонці має працювати наступне; насправді він може бути використаний для створення цілої матриці різних видів декоративного простору:
$ printf '=%.0s' `jot 64` | fold -16
================
================
================
================$
На жаль, ми не отримуємо зворотного нового рядка; які можна зафіксувати додатково printf '\n'
після складки:
$ printf "=%.0s" `jot 64` | fold -16 ; printf "\n"
================
================
================
================
$
Список літератури:
Моя пропозиція (приймаючи змінні значення для n):
n=100
seq 1 $n | xargs -I {} printf =