Как я мог сделать это с 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 =
сек.
repl = 100
(eval
, к сожалению, требуется хитрость, чтобы основать расширение фигурных скобок на переменной): repl() { printf "$1"'%.s' $(eval "echo {1.."$(($2))"}"); }
- person mklement0; 08.12.2013
seq
, например. $(seq 1 $limit)
.
- person dogbane; 11.01.2014
repl () { printf '=%.0s' $(seq 2 $(echo $1 | wc -c)); }
Использование: repl 'Installing something'
или repl "Installing $package"
- person reubano; 01.05.2014
ksh
и zsh
, к сожалению, это просто bash
, который расширяет вещи в другом и глупом порядке.
- person Adrian Frühwirth; 02.05.2014
$s%.0s
на %.0s$s
, иначе дефисы вызовут printf
ошибку.
- person KomodoDave; 30.07.2014
n=5; eval "echo {1..$n}"
Но seq более элегантен.
- person Palec; 16.11.2014
printf
в Bash: он продолжает применять строку формата до тех пор, пока не останутся аргументы. Я предполагал, что он обработал строку формата только один раз!
- person Jeenu; 08.01.2015
w
, как насчет printf "%${w}s" '' | tr ' ' =
?
- person IpsRich; 24.07.2015
len=20; eval "printf "%0.s$c" {1..$len}"
- person rowan; 08.03.2017
echo "$(printf '=%.s' {1..100})"
- person Alex; 12.06.2017
Equals="============="
и Dashes="------------"
, определенные в глобальном разделе bash, а затем ссылались на циклы печати в локальных функциях bash для повышения производительности и удобочитаемости. Сегодня чувствую себя виноватым, но я знаю, что буду признателен за систему KISS через 5 лет.
- person WinEunuuchs2Unix; 25.06.2017
-
, вы можете поместить его в конец строки формата '%.0s-'
, иначе вы получите сообщение об ошибке, потому что начальный дефис будет интерпретирован как опция.
- person wisbucky; 09.12.2017
printf '=%.0s'
выходы =
. Так что не вариант, когда нужно произвольное количество =
. А если быть точным, произвольное количество пробелов для отступа. Решение other отлично подходит для этого случая. А именно printf "%${n}s" | tr ' ' '='
- person x-yuri; 18.09.2018
.0
в этом ответе? И это регулярное выражение или printf
- person KPCT; 16.03.2019
man 3 printf
: Необязательная точность в виде точки ('.'), За которой следует необязательная строка десятичных цифр. [..] Если точность указана как ".", Точность принимается равной нулю. [..] максимальное количество символов, которое будет напечатано из строки для преобразований s и S. Поэтому я ожидал, что он будет работать и без 0
.
- person Jonathan Komar; 21.09.2020
%
. Попробуйте добавить строку комментария в LaTeX: read !printf '\%\%\%.s' {1..50}
- person Jonathan Komar; 21.09.2020
printf '-%.0s' {1..100}
не работает
- person Angel; 24.02.2021
Непростой путь. Но например:
seq -s= 100|tr -d '[:digit:]'
Или, может быть, способ, соответствующий стандарту:
printf %100s |tr " " "="
Еще есть tput rep
, но что касается моих терминалов (xterm и linux), похоже, они его не поддерживают :)
=
символов.
- person Camilo Martin; 02.01.2014
printf
tr
- единственное решение POSIX, потому что seq
, yes
и {1..3}
не являются POSIX.
- person Ciro Santilli 新疆再教育营六四事件ۍ 10.04.2014
printf %100s | sed 's/ /abc/g'
- выводит 'abcabcabc ...'
- person John Rix; 11.09.2014
tr
). Вы также можете расширить его до чего-то вроде printf "%${COLUMNS}s\n" | tr " " "="
.
- person musiphil; 16.03.2015
seq
, похоже, возвращают ожидаемые 100 символов. когда я бегу seq -s= 100 | tr -d '[:digit:]' | wc -m
. Если у вас это действительно не работает: какую seq
реализацию вы используете?
- person mklement0; 29.04.2015
seq
8.21, я получаю на единицу меньше указанного числа; см. снимок экрана. Теперь я спрашиваю, на какой платформе вы находитесь, потому что я думал, что это последовательно. Вот снимок экрана с RaspberryPi и даже в Windows.
- person Camilo Martin; 03.05.2015
seq
(и, следовательно, неявно к платформе): GNU seq
(Linux) производит на 1 меньше =
, чем указанное число (в отличие от того, что я первоначально утверждал, но как вы правильно определили), тогда как BSD seq
(BSD-подобные платформы, включая OSX) выдает желаемое число. Простая тестовая команда: seq -s= 100 | tr -d '[:digit:]\n' | wc -c
BSD seq
помещает =
после каждого числа, включая последнее, тогда как GNU seq помещает новую строку после последнего число, таким образом, сокращается на 1 по отношению к счетчику =
.
- person mklement0; 03.05.2015
wc
. Единственный вывод, который я могу сделать из этого: seq
не следует использовать.
- person Camilo Martin; 03.05.2015
printf
решение является портативным, и его проще загружать.
- person mklement0; 04.05.2015
tput rep
работать, но прямая последовательность ANSI работает. Я думаю, что tput
не может правильно обработать termcap
синтаксис rep=%p1%c\E[%p2%{1}%-%db
или в Termcap терминала Gnome отсутствует запись. См. Мой ответ: stackoverflow.com/a/59251780/7939871
- person Léa Gris; 10.12.2019
printf
отлично работало под оболочкой POSIX. Большое спасибо.
- person Bob Jarvis - Reinstate Monica; 02.10.2020
Совет от @ gniourf_gniourf за его вклад.
Примечание. Этот ответ не отвечает на исходный вопрос, но дополняет существующие полезные ответы, сравнивая эффективность.
Решения сравниваются только по скорости выполнения - требования к памяти не учитываются (они различаются в зависимости от решения и могут иметь значение при большом количестве повторов).
Резюме:
${var// /=}
), as it is prohibitively slow.Ниже приведены тайминги, снятые на iMac конца 2012 года с процессором Intel Core i5 3,2 ГГц и накопителем Fusion Drive, работающим под OSX 10.10.4 и bash 3.2.57, и это в среднем 1000 запусков.
Записи:
M
... a potentially multi-character solutionS
... одно -символьное решение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 (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
Есть несколько способов сделать это.
Использование петли:
Раскладку скобок можно использовать с целочисленными литералами:
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
:
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
); в то время как два других решения в этом случае будут медленными, у них есть преимущество работы с многосимвольными строками.
- person mklement0; 29.04.2015
yes
и head
- полезно, если вам нужно определенное количество символов новой строки: yes "" | head -n 100
. tr
может заставить его печатать любой символ: yes "" | head -n 100 | tr "\n" "="; echo
- person loxaxs; 27.05.2018
dd if=/dev/zero count=1 bs=100000000 | tr '\0' '=' >/dev/null
значительно медленнее, чем версия head -c100000000 < /dev/zero | tr '\0' '=' >/dev/null
. Конечно, вы должны использовать размер блока 100M +, чтобы разумно измерить разницу во времени. 100 Мбайт занимает 1,7 с и 1 с для двух соответствующих версий. Я снял tr и просто сбросил его в /dev/null
и получил 0,287 с для версии head
и 0,675 с для версии dd
для миллиарда байт.
- person Michael Goldshteyn; 11.08.2018
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
;
- person 3ED; 18.08.2018
printf '-%.0s' {1..100}
не работает
- person Angel; 24.02.2021
Я только что нашел очень простой способ сделать это с помощью seq:
ОБНОВЛЕНИЕ: работает на BSD seq
, которая поставляется с OS X. YMMV с другими версиями
seq -f "#" -s '' 10
Напечатает '#' 10 раз, вот так:
##########
-f "#"
устанавливает строку формата, чтобы игнорировать числа и просто печатать #
для каждого из них.-s ''
устанавливает разделитель на пустую строку, чтобы удалить символы новой строки, которые seq вставляет между каждым числом-f
и -s
кажутся важными.РЕДАКТИРОВАТЬ: Вот это удобная функция ...
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
- person John B; 07.07.2014
seq
здесь ловко перепрофилируется для репликации строк: строка формата, переданная в -f
- обычно используется для форматирования генерируемых чисел - содержит только строку для репликации здесь, так что вывод содержит только копии этой строки. К сожалению, GNU seq
настаивает на наличии числового формата в строке формата, и это ошибка, которую вы видите.
- person mklement0; 29.04.2015
"$1"
(двойные кавычки), чтобы вы также могли передавать символы, такие как '*'
, и строки со встроенными пробелами. Наконец, если вы хотите использовать %
, вы должны удвоить его (иначе seq
будет думать, что это часть спецификации формата, такой как %f
); использование "${1//%/%%}"
позаботится об этом. Поскольку (как вы упомянули) вы используете BSD seq
, этот будет работать с BSD-подобными ОС в целом (например, FreeBSD) - напротив, он не будет работать в Linux, где используется GNU seq
.
- person mklement0; 29.04.2015
-f
и "#"
пробел не необходим, потому что аргумент-параметр непустой. Он является обязательным после -s
, потому что технически невозможно передать пустую строку в качестве аргумента-параметра, непосредственно присоединяя ее к -s
: оболочке удаляет кавычки из строки -s''
перед передачей в seq
, поэтому seq
будет видеть только -s
. #
- не единственный символ, который нужно заключать в кавычки - также можно использовать так называемые метасимволы оболочки и *
; лучше просто всегда цитировать.
- person mklement0; 29.04.2015
BD_H="\xE2\x94\x80"; repeat "${BD_H}" 20
отображает 20 пробелов.
- person Andris; 27.04.2017
Вот два интересных способа:
ubuntu@ubuntu:~$ yes = | head -10 | paste -s -d '' - ========== ubuntu@ubuntu:~$ yes = | head -10 | tr -d "\n" ==========ubuntu@ubuntu:~$
Обратите внимание, что эти два элемента немного отличаются - метод paste
заканчивается новой строкой. Метод tr
- нет.
paste
необъяснимо требует -d '\0'
для указания пустого разделителя и не работает с -d ''
- -d '\0'
должен работать со всеми POSIX-совместимыми реализациями paste
и действительно также работает с GNU paste
.
- person mklement0; 29.04.2015
yes | mapfile -n 100 -C 'printf = \#' -c 1
- person bishop; 27.04.2016
time yes = | head -500 | paste -s -d '\0' -; time yes | mapfile -n 500 -C 'printf = \#' -c 1
. Но что еще более важно: если вы все равно используете printf
, вы можете использовать как более простой, так и более эффективный подход из принятого ответа: printf '%.s=' $(seq 500)
- person mklement0; 17.07.2016
Нет простого пути. Избегайте циклов с использованием printf
и подстановки.
str=$(printf "%40s")
echo ${str// /rep}
# echoes "rep" 40 times.
repl = 100
(не выводит завершающий \n
): repl() { local ts=$(printf "%${2}s"); printf %s "${ts// /$1}"; }
- person mklement0; 07.12.2013
printf -v str …
вместо str=$(printf …)
, чтобы не вызывать подоболочку. И для общего решения я бы использовал printf "%s" "${str// /rep}"
вместо echo
, потому что printf
более надежен и не подавляется строками, начинающимися с -
, как это делает echo
.
- person musiphil; 08.05.2021
Вопрос был в том, как это сделать с echo
:
echo -e ''$_{1..100}'\b='
Это будет делать то же самое, что и perl -E 'say "=" x 100'
, но только с echo
.
$_1
, $_2
или любая другая из сотни переменных имеют значения.
- person John Kugelman; 09.11.2019
Если вам нужна совместимость с 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
).
- person mklement0; 29.04.2015
cal
- это POSIX. seq
нет. В любом случае, вместо того, чтобы переписывать ответ с помощью цикла while (как вы говорите, это уже есть в других ответах), я добавлю функцию RYO. Это более познавательно ;-).
- person Geoff Nixon; 03.05.2015
Чистый способ 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 ГГц : При счете 1000 все идет медленно (3.2.57
) / быстро (4.3.30
): 0,1 / 0,004 секунды. Увеличение числа до 10 000 дает совершенно разные числа: repeat 10000 = var
занимает около 80 секунд (!) В bash 3.2.57
и около 0,3 секунды в bash 4.3.30
(намного быстрее, чем в 3.2.57
, но все же медленно).
- person mklement0; 29.04.2015
Вот что я использую для печати строки символов на экране в Linux (в зависимости от ширины терминала / экрана)
printf '=%.0s' $(seq 1 $(tput cols))
Пояснение:
Выведите знак равенства столько раз, сколько заданная последовательность:
printf '=%.0s' #sequence
Используйте вывод команды (это функция bash, называемая подстановкой команд):
$(example_command)
Приведите последовательность, я использовал в качестве примера от 1 до 20. В последней команде вместо 20 используется команда tput:
seq 1 20
Укажите количество столбцов, которые в настоящее время используются в терминале:
tput cols
printf '-%.0s' {1..100}
не работает
- person Angel; 24.02.2021
#!/usr/bin/awk -f
BEGIN {
OFS = "="
NF = 100
print
}
Or
#!/usr/bin/awk -f
BEGIN {
while (z++ < 100) printf "="
}
awk 'BEGIN { while (c++ < 100) printf "=" }'
. Обернутая в параметризованную функцию оболочки (например, вызывается как repeat 100 =
): repeat() { awk -v count="$1" -v txt=".$2" 'BEGIN { txt=substr(txt, 2); while (i++ < count) printf txt }'; }
. (Пустой префикс .
char и дополнительный вызов substr
необходимы для обхода ошибки в BSD awk
, где передача значения переменной, которая начинается с =
, прерывает команду.)
- person mklement0; 29.04.2015
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 }'; }
.
- person mklement0; 14.05.2015
original-awk
- это имя под Linux более старой awk, похожей на BSD awk, которая, как сообщалось, вылетала из строя, если вы хотите попробовать это. Обратите внимание, что сбой обычно является первым шагом к обнаружению уязвимой ошибки. Этот ответ настолько продвигает небезопасный код.
- person ; 25.08.2015
original-awk
нестандартно и не рекомендуется
- person Steven Penny; 26.08.2015
awk NF=100 OFS='=' <<< ""
(с использованием bash
и gawk
)
- person oliv; 24.05.2018
Еще один способ повторить произвольную строку 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. Вы можете использовать escape-последовательность ANSI CSI. Это самый быстрый способ повторить символ.
#!/usr/bin/env bash
char='='
repeat_count=80
printf '%c\e[%db' "$char" "$repeat_count"
Или статически:
Выведите строку 80 раз =
:
printf '=\e[80b\n'
Ограничения:
repeat_char
ANSI CSI.repeat_char
ANSI CSI не преобразуется в повторяющийся символ.В bash 3.0 или выше
for i in {1..100};do echo -n =;done
Я предполагаю, что первоначальная цель вопроса заключалась в том, чтобы сделать это только с помощью встроенных команд оболочки. Таким образом, for
циклы и printf
будут допустимы, а rep
, perl
, а также jot
ниже - нет. Тем не менее, следующая команда
jot -s "/" -b "\\" $((COLUMNS/2))
например, печатает строку \/\/\/\/\/\/\/\/\/\/\/\/
во всю ширину окна
jot -s '' -b '=' 100
. Предостережение заключается в том, что, хотя платформы, подобные BSD, включая OSX, поставляются с jot
, дистрибутивы Linux не имеют.
- person mklement0; 29.04.2015
apt install athena-jot
предоставит jot
.
- person agc; 08.02.2019
Как уже говорили другие, в bash расширение фигурных скобок предшествует расширение параметра, поэтому {m,n}
диапазоны могут содержать только литералы. seq
и _ 3_ предоставляют чистые решения, но не полностью переносимы из одной системы в другую, даже если вы используете одну и ту же оболочку на каждой. (Хотя 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
(заканчивается новой строкой).
Деннис Уильямсон дал по существу это решение четыре года назад в его превосходном ответе на Создание строки повторяющихся символы в сценарии оболочки. Тело моей функции немного отличается от приведенного там кода:
Поскольку здесь основное внимание уделяется повторению одного символа, а оболочка - bash, вероятно, безопасно использовать echo
вместо printf
. И я прочитал описание проблемы в этом вопросе как выражение предпочтения печати с использованием echo
. Приведенное выше определение функции работает в bash и ksh93. Хотя printf
более переносимый (и обычно его следует использовать для такого рода вещей), синтаксис echo
, возможно, более читабелен.
Некоторые echo
встроенные командные интерпретаторы интерпретируют -
как вариант - даже несмотря на то, что обычное значение -
, использовать stdin для ввода, бессмысленно для echo
. Это делает zsh. И определенно существуют echo
, которые не распознают -n
, поскольку это не стандартно < / а>. (Многие оболочки в стиле Борна вообще не принимают циклы for в стиле C, поэтому их echo
поведение не нужно учитывать ..)
Здесь задача - распечатать последовательность; там, это должно было назначить его переменной.
Если $n
- желаемое количество повторений, и вам не нужно его повторно использовать, и вы хотите что-то еще короче:
while ((n--)); do echo -n "$s"; done; echo
n
должен быть переменной - этот способ не работает с позиционными параметрами. $s
- текст, который нужно повторить.
printf "%100s" | tr ' ' '='
оптимально.
- person ocodo; 04.11.2014
zsh
. Подход «эхо-в-цикле» хорошо работает для меньшего количества повторов, но для большего количества есть POSIX-совместимые альтернативы на основе утилит, о чем свидетельствует комментарий @ Slomojo.
- person mklement0; 29.04.2015
(while ((n--)); do echo -n "$s"; done; echo)
- person ; 23.08.2015
echo
, которая поддерживает -n
. Смысл того, что вы говорите, абсолютно правильный. printf
почти всегда следует предпочесть echo
, по крайней мере, при неинтерактивном использовании. Но я не думаю, что было каким-либо образом неуместным или вводящим в заблуждение echo
ответ на вопрос, в котором был задан один и который дал достаточно информации, чтобы знать, что это сработает. Также обратите внимание, что поддержка ((n--))
(без $
) сама по себе не гарантируется POSIX.
- person Eliah Kagan; 14.02.2020
Python повсеместен и везде работает одинаково.
python -c "import sys; print('*' * int(sys.argv[1]))" "=" 100
Символ и количество передаются как отдельные параметры.
python -c "import sys; print(sys.argv[1] * int(sys.argv[2]))" "=" 100
- person gazhay; 21.02.2020
В случае, если вы хотите повторить символ n раз, будучи n ПЕРЕМЕННОЙ количество раз в зависимости, скажем, от длины строки, вы можете:
#!/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, которому OP ищет альтернативу Bash.
- person mklement0; 07.08.2015
Это более длинная версия того, что поддерживал Элиа Каган:
while [ $(( i-- )) -gt 0 ]; do echo -n " "; done
Конечно, вы можете использовать и printf для этого, но мне это не очень нравится:
printf "%$(( i*2 ))s"
Эта версия совместима с Dash:
until [ $(( i=i-1 )) -lt 0 ]; do echo -n " "; done
где i - начальное число.
while (( i-- )); do echo -n " "; done
работает.
- person ; 23.08.2015
Самый простой - использовать этот однострочник в csh / tcsh:
printf "%50s\n" '' | tr '[:blank:]' '[=]'
Другой вариант - использовать GNU seq и удалить все генерируемые числа и символы новой строки:
seq -f'#%.0f' 100 | tr -d '\n0123456789'
Эта команда печатает символ #
100 раз.
echo $(seq -f'#' 100 | tr -d '\n')
- person Coroos; 11.09.2020
Не для того, чтобы нагромождать, но другой подход, основанный на чистом Bash, использует ${//}
подстановку массивов:
$ arr=({1..100})
$ printf '%s' "${arr[@]/*/=}"
====================================================================================================
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
Как я мог сделать это с помощью эха?
Вы можете сделать это с помощью echo
, если за echo
следует sed
:
echo | sed -r ':a s/^(.*)$/=\1/; /^={100}$/q; ba'
Собственно, в этом echo
нет необходимости.
Мой ответ немного сложнее и, вероятно, не идеален, но для тех, кто хочет выводить большие числа, я смог сделать около 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
Более элегантной альтернативой предлагаемому решению Python может быть:
python -c 'print "="*(1000)'
Большинство существующих решений зависят от {1..10}
поддержки синтаксиса оболочки, которая зависит от bash
и zsh
, и не работает в tcsh
или OpenBSD _ 5_ и большинство не-bash sh
.
Следующее должно работать в OS 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 =
Немного более длинная версия, но если вам по какой-то причине нужно использовать чистый Bash, вы можете использовать цикл while с увеличивающейся переменной:
n=0; while [ $n -lt 100 ]; do n=$((n+1)); echo -n '='; done
printf -- '=%.0s' {1..100}
Двойное тире --
означает конец флагов командной строки, поэтому не пытайтесь разбирать то, что идет после параметров командной строки.
Если вы хотите напечатать символ тире -
, а не символ =
, несколько раз и не включать двойной тире --
, вот что вы получите:
$ printf '-%.0s' {1..100}
bash: printf: -%: invalid option
printf: usage: printf [-v var] format [arguments]
Почему бы не создать такую однострочную функцию:
function repeat() { num="${2:-100}"; printf -- "$1%.0s" $(seq 1 $num); }
Тогда вы можете назвать это так:
$ repeat -
----------------------------------------------------------------------------------------------------
или вот так:
$ repeat =
====================================================================================================
или вот так:
$ repeat '*' 8
********
n=5; chr='x'; chr_string='';
for (( i=0; $i<$n; i++ ))
do
chr_string=$chr_string$chr
done
echo -n "$chr_string"
Работает для ...
n = целое число (включая ноль и отрицательное число).
chr = печатаемое и пробел (пробел и табуляция).
ruby -e 'puts "=" * 100'
илиpython -c 'print "=" * 100'
- person Evgeny   schedule 20.04.2017printf
сseq
)svrb=`printf '%.sv' $(seq $vrb)`
- person DrBeco   schedule 07.07.2017