Как создать последовательность циклов?

Я пытаюсь создать сценарий, который будет получать одну переменную от пользователя и должен печатать пирамиду, как показано ниже:

* ** *** **** ***** 

Я использовал этот скрипт, но он показывает мне номера:

 for i in {1..5} do a=${a}${i} echo ${a} done 

выход:

 1 12 123 1234 12345 

Как добавить знак «*» вместо цифр?

4 Solutions collect form web for “Как создать последовательность циклов?”

Просто добавьте символ * к переменной, а не счетчик циклов:

 for i in {1..5} do a+='*' echo "${a}" done 

Обратите внимание, что a="${a}*" вместо a+='*' работает так же хорошо, но я думаю, что версия += опрятно / понятна.

Если вы хотите сделать это с помощью цикла while, вы можете сделать что-то вроде этого:

 while (( "${#a}" < 5 )); do a+='*' echo "$a" done 

${#a} расширяется до длины строки в переменной.

Обратите внимание, что оба вышеуказанных фрагмента кода (а также код в вопросе) предполагают, что a var пуст или не установлен в начале фрагмента. Если это не так, вам нужно сначала его инициализировать:

 a= 

Я предполагаю, что вы используете оболочку bash. Вот полное руководство. Вот раздел о циклах.

Ответ на цифровую травму более эффективен в этом случае, но для полноты вы можете использовать традиционный метод оболочки повторяющихся символов с помощью printf :

 for i in {1..5} do printf "%${i}s\n" done | sed 's/ /*/g' 

Это использует printf для вывода как можно большего количества пробелов, а затем sed заменяет пробелы символом, который мы действительно хотим.

Как отметили Digital Trauma и Janis , вы можете сохранить результат printf в переменной и использовать замену подстроки оболочки, чтобы избежать использования sed (за счет нереста много подоболочек во многих случаях):

 for i in {1..5} do a=$(printf "%${i}s") echo "${a// /*}" done 

Кавычки необходимы с echo здесь, чтобы избежать интерпретации символов * . Кроме того, с echo \n больше не требуется.

Как указано kojiro , tr больше подходит для замены одиночных символов, чем sed :

 for i in {1..5} do printf "%${i}s\n" done | tr ' ' '*' 

(Но вариант sed позволяет повторять текст любой длины.)

POSIXly:

 $ n=5 awk 'BEGIN{OFS="*";for(i=2;i<=ENVIRON["n"]+1;i++){$i="";print}}' 

Во-первых, вот некоторые примерные сравнения некоторых других предлагаемых решений:

 time \ bash -c ' for i in {1..1000} do printf "%0${i}s\n" done| sed "y/ /*/" ' >/dev/null real 0m0.017s user 0m0.023s sys 0m0.000s 

Это неплохо, хотя я добавил небольшую оптимизацию с помощью выражения y/ /*/ translation, а не оператора подстановки регулярного выражения s/ /*/g .

 time \ bash -c ' for i in {1..1000} do a=$(printf "%0${i}s") echo "${a// /*}" done ' >/dev/null real 0m1.337s user 0m0.723s sys 0m0.187s 

Вау. Это ужасно.

Вот один из них, который я бы предложил вам использовать, если бы вы действительно были наклонены на решение только для оболочки. Преимущество этого в сравнении с другим тестируемым заключается в том, что, в первую очередь, ему не нужно устанавливать две переменные – только один из них установлен, и это $IFS и это только один раз. Он также не развивает дочернюю оболочку на итерацию, что, как правило, не очень хорошая идея.

Он полагается на механизм замещения в $* для полей в $@ . Поэтому он просто добавляет новый нулевой позиционный элемент для каждой итерации. Также обратите внимание на то, что он избегает расширения for {1..1000} расточительной скобки.

 time \ bash -c ' IFS=\*; set "" until [ "$#" -gt 1001 ] do set "" "$@" echo "$*" done ' >/dev/null real 0m0.755s user 0m0.753s sys 0m0.000s 

Хотя он в два раза быстрее, чем другое решение только для оболочки, оно все еще довольно ужасно.

Это немного лучше – все идет наоборот. Вместо того, чтобы расширять "$@" чтобы получить нужные значения, он строит его по экспоненте и постепенно расширяет его:

 time \ bash -c ' set \*;n=0 IFS= until [ "$#" -gt 512 ] do set "$@" "$@" shift "$(($#>1000?24:0))" until [ "$n" -eq "$#" ] do printf %."$((n+=1))s\n" "$*" done; done ' >/dev/null real 0m0.158s user 0m0.157s sys 0m0.020s 

Чтобы избить свое собственное предложение только для снаряжения, ну, много, (по крайней мере, с bash dash выполняющим вышеизложенное, и bash делающим ниже, – шея и шея) :

 time \ bash -c 'a= for i in {1..1000} do a+=\* echo "$a" done ' >/dev/null real 0m0.020s user 0m0.017s sys 0m0.000s 

Это обнадеживает – казалось бы, bash оптимизирует форму a+= чтобы на самом деле сделать append, а не полный re-eval / re-assign. Во всяком случае, sed все еще бьет его.

sed выше не бьет awk , хотя:

 time \ bash -c ' n=1000 \ awk "BEGIN{OFS=\"*\";for(i=2;i<=ENVIRON[\"n\"]+1;i++){\$i=\"\";print}}" ' >/dev/null real 0m0.010s user 0m0.007s sys 0m0.000s 

… который является самым быстрым.

Но никто не бил другого sed который в основном делает то, что моя функция nstars (вы найдете ниже) будет делать, если вы сделали nstars 1000 :

 time \ bash -c ' printf %01000s | sed -ne "H;x;:loop s/\(\n\)./*1/ P;//t loop" ' >/dev/null real 0m0.007s user 0m0.000s sys 0m0.003s 

… который является самым быстрым. (при запуске со time nstars 1000 >/dev/null реальный результат был .006s ) . На нем ниже.

Другое решение для POSIX:

 echo Type some stuff: sed -ne 'H;x;:loop s/\(\n\)./*\1/ P;//!q;t loop' 

Вставьте вышеуказанное прямо в свой терминал, введите любую строку и нажмите Enter . Вы увидите пирамиду * s, одну строку для каждого введенного вами символа. 3-символьная строка даст три строки, 4-символьный будет печатать 4 и т. Д.

sed отлично способен считывать вход tty и манипулировать им, как вам нравится. В этом случае он читает строку от пользователя, помещает \n ewline в начало строки, в которую будет считываться, а затем рекурсивно заменяет \n строку и символ, сразу после нее, с символом * и \n ewline, все в то время как P разворачивается только до \n ewline каждый раз.

Поскольку это так, пространство с образцом на самом деле выглядит так (я просто поменял команду P rint для l ook) :

 here's some stuff *\nere's some stuff$ **\nre's some stuff$ ***\ne's some stuff$ ****\n's some stuff$ *****\ns some stuff$ ******\n some stuff$ *******\nsome stuff$ ********\nome stuff$ *********\nme stuff$ **********\ne stuff$ ***********\n stuff$ ************\nstuff$ *************\ntuff$ **************\nuff$ ***************\nff$ ****************\nf$ *****************\n$ 

Верхняя строка была моим вкладом. С P , хотя:

 here's some stuff * ** *** **** ***** ****** ******* ******** ********* ********** *********** ************ ************* ************** *************** **************** ***************** 

Если вы хотите остановить его в 5, например, вы можете добавить тест /.\{5\}\n/ , например:

 echo Type some stuff: sed -ne 'H;x;:loop s/\(\n\)./*\1/ P;//!q;/.\{5\}\n/q t loop' 

Вы можете сгенерировать строки таким же образом:

 nstars()( n=${1##*[!0-9]*} shift "$((!!n))" if [ -n "${n:-$1}" ] then printf %0"$n"s "$*" else [ -t 0 ] && echo Type some stuff: >&0 head -n 1 fi | sed -ne 'H;x;:loop s/\(\n\)./*\1/ P;//t loop' ) 

Там, с этим вы можете дать числовой первый аргумент, и sed будет печатать звезды рекурсивно до вашего счета, или вы можете дать один или несколько аргументов строки, а sed будет печатать звезды для всех символов в строке или вы можете запустить их на терминале, и он предложит одну строку ввода и печати для этого, или он будет обрабатывать любые другие входные данные без запроса.

 { nstars 3 nstars three echo 3please | nstars nstars } 

ВЫВОД:

 * ** *** * ** *** **** ***** * ** *** **** ***** ****** ******* Type some stuff: ok * ** 
  • Как вы можете восстановить повреждение диска на резервном диске, сохраняя при этом все жесткие ссылки?
  • создайте массив дат в сценариях bash и сопоставьте его текущей дате
  • Как использовать awk для исправления и унификации поврежденного файла с несколькими столбцами и строками?
  • Использование памяти бесконечно циклического сценария оболочки
  • Как печатать IP / MASK из списка?
  • Сценарий для удаления текстовых файлов
  • Параллельное выполнение сценария bash
  • UNIX - команда разбивать файл на несколько файлов со всеми строками для каждых 3 уникальных значений в столбце
  • Как вычислить процент столбца файла?
  • Найти все физические интерфейсы во FreeBSD
  • Извлечение каталога из stdout из wget
  • Linux и Unix - лучшая ОС в мире.