Советы по игре в гольф в Баше

55

Какие общие советы у вас есть для игры в гольф в Баше? Я ищу идеи, которые могут быть применены к кодовым проблемам гольфа в целом, которые, по крайней мере, несколько специфичны для Bash (например, «удалить комментарии» - это не ответ). Пожалуйста, оставьте один совет за ответ.

manatwork
источник

Ответы:

36

Недокументированный , но работает в каждой версии, с которой я столкнулся для устаревшейshобратной совместимости:

forЦиклы позволяют использовать { }вместо do done. Например, заменить:

for i in {1..10};do echo $i; done

с участием:

for i in {1..10};{ echo $i;}
Цифровая травма
источник
что такое оболочка shи какая оболочка допускает этот forсинтаксис? это прямо разрешено в zsh.
mikeserv
@mikeserv Bash. Я помню, как читал где-то, что этот синтаксис был разрешен в некоторых старых shи что Bash также позволяет это, хотя, к сожалению, у меня нет цитаты.
Цифровая травма
ааа ... cshнаверное - так они работали в этой оболочке.
mikeserv
кстати, в ksh93вышеупомянутой вещи может быть:, ;{1..10}а в bash:printf %s\\n {1..10}
mikeserv
1
for((;i++<10)){ echo $i;}корочеfor i in {1..10};{ echo $i;}
Эван Кралл
29

Для арифметического расширения используйте $[…]вместо $((…)):

bash-4.1$ echo $((1+2*3))
7

bash-4.1$ echo $[1+2*3]
7

В арифметических расширениях не используйте $:

bash-4.1$ a=1 b=2 c=3

bash-4.1$ echo $[$a+$b*$c]
7

bash-4.1$ echo $[a+b*c]
7

Арифметическое расширение выполняется для индексов индексированных массивов, поэтому не используйте их $там:

bash-4.1$ a=(1 2 3) b=2 c=3

bash-4.1$ echo ${a[$c-$b]}
2

bash-4.1$ echo ${a[c-b]}
2

В арифметических расширениях не используйте ${…}:

bash-4.1$ a=(1 2 3)

bash-4.1$ echo $[${a[0]}+${a[1]}*${a[2]}]
7

bash-4.1$ echo $[a[0]+a[1]*a[2]]
7
manatwork
источник
Замена while((i--)), которая работает, с while[i--]или while $[i--]не работает для меня. GNU bash, версия 4.3.46 (1)
Гленн Рандерс-Персон,
1
Правильно, @ GlennRanders-Pehrson. Это не должно работать.
manatwork
y=`bc<<<"($x*2.2)%10/1"`... пример использования bcдля нецелочисленных вычислений ... обратите внимание, что /1в конце усечение результирующего десятичного числа до целого .
Роблогия
s=$((i%2>0?s+x:s+y))... пример использования тернарного оператора в арифметике bash. Это короче if..then..elseили[ ] && ||
roblogic
1
@ Manatwork Спасибо. Должно быть, они удалили это. Я нахожусь, GNU bash, version 5.0.2(1)-release (x86_64-apple-darwin16.7.0)и это не в моем.
Иона
19

Нормальный, длинный и скучный способ определения функции

f(){ CODE;}

Как выяснил этот парень , вам обязательно нужно пробел до CODEи точка с запятой после него.

Это небольшой трюк, который я узнал от @DigitalTrauma :

f()(CODE)

Это на два символа короче, и это работает так же хорошо, при условии, что вам не нужно переносить какие-либо изменения в значения переменных после возврата функции ( скобки запускают тело в подоболочке ).

Как указывает @ jimmy23013 в комментариях, даже скобки могут быть ненужными.

В Руководстве Bash Reference показывает , что функции могут быть определены следующим образом :

name () compound-command [ redirections ]

или же

function name [()] compound-command [ redirections ]

Команда соединения может быть:

  • циклическую Construct: until, whileилиfor
  • условную Construct: if, case, ((...))или[[...]]
  • Сгруппированные команды: (...)или{...}

Это означает, что все следующие условия действительны:

$ f()if $1;then $2;fi
$ f()($1&&$2)
$ f()(($1))                # This one lets you assign integer values

И я использовал фигурные скобки, как присоски ...

Деннис
источник
2
Обратите внимание, что вы также можете использовать f()while ... f()if ...и другие составные команды.
jimmy23013
Этот удивил меня, потому что я думал, что f()CODEэто законно. Оказывается, что f()echo hiэто разрешено в pdksh и zsh, но не в bash.
Kernigh
1
это особенно полезно с /, forтак как по умолчанию он позиционируется: f()for x do : $x; done;set -x *;PS4=$* f "$@"или что-то еще.
mikeserv
16

:это команда, которая ничего не делает, ее состояние выхода всегда успешно, поэтому ее можно использовать вместо true.


источник
Используя подоболочку и конвейер, он будет использовать примерно такое же количество байтов, но конвейер будет более практичным.
ckjbgames
5
За исключением случаев, когда вы это делаете:(){:|:}
enedil
14

Больше советов

  1. Злоупотреблять троичным оператором ((test)) && cmd1 || cmd2или [ test ] && cmd1 || cmd2, насколько это возможно.

    Примеры (длина отсчета всегда исключает верхнюю строку):

    t="$something"
    if [ $t == "hi" ];then
    cmd1
    cmd2
    elif [ $t == "bye" ];then
    cmd3
    cmd4
    else
    cmd5
    if [ $t == "sup" ];then
    cmd6
    fi
    fi

    Используя только троичные операторы, это можно легко сократить до:

    t="$something"
    [ $t == "hi" ]&&{
    cmd1;cmd2
    }||[ $t == "bye" ]&&{
    cmd3;cmd4
    }||{
    cmd5
    [ $t == "sup" ]&&cmd6
    }

    Как отметили в комментариях nyuszika7h, этот конкретный пример может быть сокращен еще больше, используя case:

    t="$something"
    case $t in "hi")cmd1;cmd2;;"bye")cmd3;cmd4;;*)cmd5;[ $t == "sup" ]&&cmd6;esac
  2. Кроме того, предпочитайте скобки как можно больше скобок. Поскольку круглые скобки являются метасимволами, а не словом, они никогда не требуют пробелов в любом контексте. Это также означает запуск максимально возможного количества команд в подоболочке, потому что фигурные скобки (то есть {и }) являются зарезервированными словами, а не метасимволами, и поэтому для правильного синтаксического анализа должны иметь пробелы с обеих сторон, а метасимволы - нет. Я предполагаю, что вы уже знаете, что подоболочки не влияют на родительскую среду, поэтому, предполагая, что все примеры команд могут безопасно выполняться в подоболочке (что не типично в любом случае), вы можете сократить приведенный выше код до этой :

    t=$something
    [ $t == "hi" ]&&(cmd1;cmd2)||[ $t == "bye" ]&&(cmd3;cmd4)||(cmd5;[ $t == "sup" ]&&cmd6)

    Кроме того, если вы не можете, использование скобок все еще может минимизировать его. Следует иметь в виду, что он работает только для целых чисел, что делает его бесполезным для целей этого примера (но это намного лучше, чем -eqдля целых чисел).

  3. Еще одна вещь, избегайте кавычек, где это возможно. Используя приведенный выше совет, вы можете в дальнейшем его минимизировать. Пример:

    t=$something
    [ $t == hi ]&&(cmd1;cmd2)||[ $t == bye ]&&(cmd3;cmd4)||(cmd5;[ $t == sup ]&&cmd6)
  4. В условиях тестирования предпочитайте одинарные скобки двойным скобкам, насколько это возможно, за некоторыми исключениями. Он отбрасывает два символа бесплатно, но в некоторых случаях он не так надежен (это расширение Bash - см. Пример ниже). Кроме того, используйте единственный аргумент равенства, а не двойной. Это свободный персонаж, чтобы бросить.

    [[ $f == b ]]&&: # ... <-- Bad
    [ $f == b ]&&: # ... <-- Better
    [ $f = b ]&&: # ... <-- Best.  word splits and pathname-expands the contents of $f.  Esp. bad if it starts with -

    Обратите внимание на это предостережение, особенно при проверке нулевого вывода или неопределенной переменной:

    [[ $f ]]&&:    # double quotes aren't needed inside [[, which can save chars
    [ "$f" = '' ]&&: <-- This is significantly longer
    [ -n "$f" ]&&:

    Во всех технических аспектах этот конкретный пример был бы лучше всего с case... in:

    t=$something
    case $t in hi)cmd1;cmd2;;bye)cmd3;cmd4;;*)cmd5;[ $t == sup ]&&cmd6;esac

Итак, мораль этого поста такова:

  1. Используйте как можно больше булевых операторов и всегда используйте их вместо if/ if-else/ etc. конструкты.
  2. Используйте как можно больше скобок и выполняйте как можно больше сегментов в подоболочках, потому что скобки являются метасимволами, а не зарезервированными словами.
  3. Избегайте кавычек настолько физически, насколько это возможно.
  4. Проверьте case... in, так как это может сэкономить немало байтов, особенно при сопоставлении строк.

PS: Вот список метасимволов, распознаваемых в Bash независимо от контекста (и может разделять слова):

&lt; &gt; ( ) ; & | &lt;space&gt; &lt;tab&gt;

РЕДАКТИРОВАТЬ: Как указал manatwork, тест с двойными скобками работает только для целых чисел. Кроме того, косвенно, я обнаружил, что вам нужно иметь пробел вокруг ==оператора. Исправил мой пост выше.

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

Isiah Meadows
источник
Извините, но у вас есть серьезные ошибки. [ $t=="hi" ]всегда будет иметь значение 0, поскольку оно анализируется как [ -n "STRING" ]. (($t=="hi"))всегда будет иметь значение 0, пока $ t имеет нечисловое значение, поскольку строки арифметических вычислений приводятся к целым числам. Некоторые тестовые случаи: pastebin.com/WefDzWbL
manatwork
@manatwork Спасибо за улов. Я обновлю соответственно.
Isiah Meadows
Использование здесь caseбудет короче. Кроме того, вам не нужно место до }, но вы делаете после {.
nyuszika7h
1
Почему бы =быть менее надежным, чем ==? =поручено POSIX, ==нет.
Деннис
1
Вопрос требует один совет за ответ ...
Тоби Спейт
7

Вместо того grep -E, grep -F, grep -r, использование egrep, fgrep, rgrep, экономия двух символов. Более короткие устарели, но работают нормально.

(Вы просили один совет за ответ!)


источник
1
Не слишком плохо там нет Pgrepдля grep -P. Хотя я вижу, как это можно легко спутать с тем pgrep, что используется для поиска процессов.
nyuszika7h
1
@ nyuszika7h Я лично grep -oмного
Разве это не сэкономит 3, включая место?
ckjbgames
7

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

$ a=(code golf)
$ echo ${a[0]}
code
$ echo $a
code
$ 
Цифровая травма
источник
7

Если вам нужно передать содержимое переменной в STDIN следующего процесса в конвейере, обычно выводить переменную в конвейер. Но вы можете добиться того же с помощью <<< строки bash здесь :

$ s="code golf"
$ echo "$s"|cut -b4-6
e g
$ cut -b4-6<<<"$s"
e g
$ 
Цифровая травма
источник
2
Так как мы играть в гольф, s=code\ golf, echo $s|и <<<$s(имея в виду , что последние две работы только потому , что есть не повторяющиеся пробелы и т.д.).
Деннис
6

Избегайте $( ...command... ), есть альтернатива, которая сохраняет один символ и делает то же самое:

` ...command... `

источник
9
Иногда $( )требуется, если у вас есть вложенные подстановки команд; в противном случае вам придется бежать изнутри``
Digital Trauma
1
Технически они делают разные вещи, я должен был использовать обратные метки вместо того, $()когда я хотел, например, выполнить замену на своем компьютере вместо scpцелевого. В большинстве случаев они идентичны.
подземный
2
@undergroundmonorail: вам никогда не нужны спины. Все, что они могут сделать, $()может сделать, если вы правильно цитируете вещи. (если вам не нужна ваша команда, чтобы пережить что-то, что бросается в глаза, $но не отступает ). Есть некоторые тонкие различия в цитировании вещей внутри них. mywiki.wooledge.org/BashFAQ/082 объясняет некоторые различия. Если вы не играете в гольф, никогда не используйте спины.
Питер Кордес
@PeterCordes Я уверен, что был способ, но все, что я пробовал в то время, не работало. Даже если спины были не лучшим решением, я был рад, что знал о них, потому что это было единственное решение, которое у меня было. ¯ \ _ (ツ) _ / ¯
подземный
@DigitalTrauma Образец вложенности: echo `bc <<<"\`date +%s\`-12"`... (Сложно опубликовать образец, содержащий обратные пометки в комментариях, там!)
Ф. Хаури
6

Используйте ifдля группировки команд

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

Если у вас есть группа команд, оканчивающаяся на if:

a&&{ b;if c;then d;else e;fi;}
a&&(b;if c;then d;else e;fi)

ifВместо этого вы можете заключить команды в условие:

a&&if b;c;then d;else e;fi

Или если ваша функция заканчивается на if:

f(){ a;if b;then c;else d;fi;}

Вы можете удалить брекеты:

f()if a;b;then c;else d;fi
jimmy23013
источник
1
Вы можете использовать троичный оператор [test] && $if_true || $elseв этих функциях и сохранить несколько байтов.
ckjbgames
Кроме того, вам не нужно места вокруг &&и||
roblogic
6

Используйте арифметику (( ... ))для условий

Вы можете заменить:

if [ $i -gt 5 ] ; then
    echo Do something with i greater than 5
fi

по

if((i>5));then
    echo Do something with i greater than 5
fi

(Примечание: после этого места нет if)

или даже

((i>5))&&{
    echo Do something with i greater than 5
}

... или если только одна команда

((i>5))&&echo Echo or do something with i greater than 5

Далее: Скрыть настройку переменной в арифметической конструкции:

((i>5?c=1:0))&&echo Nothing relevant there...
# ...
((c))&&echo Doing something else if i was greater than 5

или то же самое

((c=i>5?c=0,1:0))&&echo Nothing relevant there...
# ...
((c))&&echo Doing something else if i was greater than 5

... где, если i> 5, то c = 1 (не 0;)

Ф. Хаури
источник
Вы можете сохранить 2 байта, используя [ ]вместо (()).
ckjbgames
@ckjbgames Вы уверены в этом? Какую версию Bash вы используете?
Ф. Хаури
@FHauri Я думаю, что это будет примерно то же самое с точки зрения байтов.
ckjbgames
@ckjbgames С [ ]тобой нужен знак доллара для переменной. Я не вижу, как вы могли бы сделать то же самое с такой же или меньшей длиной, используя [ ].
Ф. Хаури
Бонусный совет: если первая строка цикла for начинается с ((...))новой строки или пробела не требуется. Например, for((;10>n++;)){((n%3))&&echo $n;} попробуйте онлайн!
Примо
6

Более короткий синтаксис для бесконечных циклов (который может быть экранирован с помощью операторов breakили exit)

for((;;)){ code;}

Это короче while true;и while :;.

Если вам не нужен break( exitединственный способ уйти), вы можете вместо этого использовать рекурсивную функцию.

f(){ code;f;};f

Если вам нужен break, но вам не нужен выход и вам не нужно переносить какие-либо изменения переменных вне цикла, вы можете использовать рекурсивную функцию с круглыми скобками вокруг тела , которая запускает тело функции в подоболочке.

f()(code;f);f
Жиль "ТАК - перестань быть злым"
источник
6

Однолинейные forпетли

Арифметическое выражение, объединенное с расширением диапазона, будет оцениваться для каждого элемента в диапазоне. Например следующее:

: $[expression]{0..9}

будет оценивать expression10 раз.

Это часто значительно короче, чем эквивалентный forцикл:

for((;10>n++;expression with n)){ :;}
: $[expression with ++n]{0..9}

Если вы не возражаете, команда не обнаружила ошибки, вы можете удалить начальный :. Для итераций, превышающих 10, вы также можете использовать диапазоны символов, например, {A..z}будет повторяться 58 раз.

В качестве практического примера, следующие оба производят первые 50 треугольных чисел, каждое в своей строке:

for((;50>d++;)){ echo $[n+=d];} # 31 bytes
printf %d\\n $[n+=++d]{A..r}    # 28 bytes
Примо
источник
Вы также можете for((;0<i--;)){ f;}
повторить в
5

Зацикливаться на аргументах

Как отмечалось в цикле «for» Bash без части «in foo bar…» , вход in "$@;"in for x in "$@;"избыточен.

От help for:

for: for NAME [in WORDS ... ] ; do COMMANDS; done
    Execute commands for each member in a list.

    The `for' loop executes a sequence of commands for each member in a
    list of items.  If `in WORDS ...;' is not present, then `in "$@"' is
    assumed.  For each element in WORDS, NAME is set to that element, and
    the COMMANDS are executed.

    Exit Status:
    Returns the status of the last command executed.

Например, если мы хотим привести в квадрат все числа с заданными позиционными аргументами в Bash-скрипте или функции, мы можем сделать это.

for n;{ echo $[n*n];}

Попробуйте онлайн!

Деннис
источник
5

Альтернатива кошке

Скажем, вы пытаетесь прочитать файл и использовать его в другом месте. Что вы можете сделать, это:

echo foo `cat bar`

Если бы содержимое barбыло foobar, это напечатало бы foo foobar.

Однако есть альтернатива, если вы используете этот метод, который экономит 3 байта:

echo foo `<bar`
Okx
источник
1
Есть ли причина, по которой <barсамо по себе это не работает, но размещение его в кавычках работает?
Критиси Литос
@ Коусквак Да. Команда <помещает файл в команду, но в этом случае она выводит его в стандартный вывод из-за причуды. Обратные оценки оценивают это вместе.
Okx
Есть ли более короткий способ чтения из стандартного ввода, кроме `cat`?
Джоэл
4

Используйте [вместо [[и testкогда это возможно

Пример:

[ -n $x ]


Используйте =вместо ==для сравнения

Пример:

[ $x = y ]

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

nyuszika7h
источник
3
[Против [[может зависеть от количества требуемых котировок: pastebin.com/UPAGWbDQ
manatwork
@ Manatwork Это хороший момент.
nyuszika7h
1
Общее правило: [... ]== /bin/test, но [[... ]]! = /bin/testИ никогда не следует отдавать предпочтение [... ]более [[... ]]вне Codegolf
кошка
4

Альтернативы head

lineна три байта короче head -1, но считается устаревшим .

sed qна два байта короче head -1.

sed 9qна один байт короче head -9.

Линн
источник
1
Несмотря на то, обреченно , мы все еще можем использовать некоторое время lineот Util-Linux пакета читать одну строку.
manatwork
4

tr -cd короче чем grep -o

Например, если вам нужно сосчитать пробелы, grep -o <char>(вывести только совпадающее) дает 10 байт, а tr -cd <char>(удалить дополнение <char>) - 9.

# 16 bytes
grep -o \ |wc -l
# 15 bytes
tr -cd \ |wc -c

( источник )

Обратите внимание, что они оба дают немного разные результаты. grep -oвозвращает результаты, разделенные строкой, в то время как tr -cdвыдает их все в одной строке, поэтому trне всегда может быть благоприятным.

Kritixi Lithos
источник
4

Сократить имена файлов

В недавнем испытании я пытался прочитать файл /sys/class/power_supply/BAT1/capacity, однако его можно сократить, так /*/*/*/*/capac*yкак другого файла с таким форматом не существует.

Например, если у вас был каталог, foo/содержащий файлы, foo, bar, foobar, barfooи вы хотели сослаться на файл foo/barfoo, вы можете использовать его foo/barf*для сохранения байта.

*Представляет собой «ничего», и эквивалентен регулярное выражение .*.

Okx
источник
3

Используйте канал для :команды вместо /dev/null. :Встроенный съест все его вход.


источник
2
Нет, в большинстве случаев это приведет к сбою программы с SIGPIPE. echo a|tee /dev/stderr|:не будет ничего печатать.
jimmy23013
Существует гонка: echo a|tee /dev/stderr|:напечатал на моем компьютере, но в другом месте SIGPIPE может убить тебя первым. Это может зависеть от версии tee.
Kernigh
Да, это проблема SIGPIPE: tee >(:) < <(seq 1 10)будет работать, но tee /dev/stderr | :не будет. Даже a() { :;};tee /dev/stderr < <(seq 1 10)| aничего не печатать.
Ф. Хаури
@ user16402 - вы должны иметь fccing имя для моей области ... в любом случае, :внутренняя сущность совсем не ест ... если вы допустите ввод двоеточия, вы можете залить канал в ошибку out ... но вы можете выполнить перенаправление через двоеточие, или прекратить процесс с ним ... :| while i>&$(($??!$?:${#?})) command shit; do [ -s testitsoutput ]; doneили как бы ни применимо это псевдо-предложение ... кроме того, вы знаете, что вы почти такой же призрачный, как я? ... избегать любой ценой< <(psycho shit i can alias to crazy math eat your world; okay? anyway, ksh93 has a separate but equal composite char placement)
mikeserv
3

splitимеет другой (устарел, но никого не волнует) синтаксис для разделения ввода на разделы Nстрок каждый: вместо split -lNвы можете использовать split -Nнапример split -9.


источник
3

Развернуть тесты

По сути, оболочка - это своего рода макроязык, или, по крайней мере, гибрид или какой-то еще. Каждая командная строка может быть в основном разбита на две части: часть анализа / ввода и часть расширения / вывода.

Первая часть - это то, на чем фокусируется большинство людей, потому что она самая простая: вы видите, что получаете. Вторая часть - это то, что многие избегают даже когда-либо пытаться понять очень хорошо, и именно поэтому люди говорят, что подобные вещи evalявляются злом, и всегда цитируют ваши расширения - люди хотят, чтобы результат первой части был равен первому. Это нормально - но это приводит к излишне длинным ветвям кода и множеству посторонних тестов.

Расширения проходят самотестирование . Эти ${param[[:]#%+-=?]word}формы более чем достаточно , чтобы проверить содержимое параметра, являются вложенностью, и все они основаны вокруг оценки для NUL - которая является то , что большинство людей ожидают тестов в любом случае. +особенно удобно в циклах:

r()while IFS= read -r r&&"${r:+set}" -- "$@" "${r:=$*}";do :;done 2>&-

IFS=x
printf %s\\n some lines\ of input here '' some more|{ r;echo "$r"; }

somexlines ofxinputxhere

... в то время как readтянет в не пустые строки "${r:+set}"расширяется "set"и позиционирование $rдобавляется. Но когда пустая строка read, $rпустой и "${r:+set}"расширяется ""- что является неправильной командой. Но так как командная строка расширяется до"" того ищется команда нуля, "${r:=$*}"принимают значения всех positionals сцепленной на первые байтах в $IFSа. r()может быть вызван снова в |{составной команде ;}с другим значением для того, $IFSчтобы получить также следующий входной абзац, так как для оболочки запрещено readбуферизовать после следующей \nстроки в вводе.

mikeserv
источник
3

Используйте хвостовую рекурсию, чтобы сделать петли короче:

Они эквивалентны в поведении (хотя, вероятно, не в использовании памяти / PID):

while :;do body; done
f()(body;f);f
body;exec $0
body;$0

И это примерно эквивалентно:

while condition; do body; done
f()(body;condition&&f);f
body;condition&&exec $0
body;condition&&$0

(технически последние три всегда выполнят тело хотя бы один раз)

Использование $0требует, чтобы ваш скрипт находился в файле, а не вставлялся в приглашение bash.

В конечном итоге ваш стек может переполниться, но вы сохраните несколько байтов.

Эван Кралл
источник
3

Иногда короче использовать exprвстроенную функцию для отображения результата простого арифметического выражения вместо обычного echo $[ ]. Например:

expr $1 % 2

на один байт короче, чем:

echo $[$1%2]
Цифровая травма
источник
2

Используйте pwdвместо того, echoчтобы генерировать строку вывода

Нужно поместить строку в стандартный вывод, но не заботиться о содержимом и хотите ограничить свой ответ встроенными командами оболочки? pwdБайт короче, чем echo.

Гленн Рандерс-Персон
источник
2

Кавычки могут быть опущены при печати строк.

echo "example"
echo example

Выход в SM-T335 LTE, Android 5.1.1:

u0_a177@milletlte:/ $ echo "example"
example
u0_a177@milletlte:/ $ echo example
example

источник
2

При назначении элементов непрерывного массива вы все равно можете пропустить последовательные индексы непрерывных блоков:

bash-4.4$ a=([1]=1 [2]=2 [3]=3 [21]=1 [22]=2 [23]=3 [31]=1)

bash-4.4$ b=([1]=1 2 3 [21]=1 2 3 [31]=1)

Результат тот же:

bash-4.4$ declare -p a b
declare -a a=([1]="1" [2]="2" [3]="3" [21]="1" [22]="2" [23]="3" [31]="1")
declare -a b=([1]="1" [2]="2" [3]="3" [21]="1" [22]="2" [23]="3" [31]="1")

По словам man bash:

Массивы присваиваются с использованием составных присваиваний в форме name = (значение 1 ... значение n ), где каждое значение имеет форму [ subscript ] = string . Индексированные массивы не требуют ничего, кроме строки . При назначении индексированным массивам, если поставляются необязательные скобки и нижний индекс, этому индексу присваивается; в противном случае индекс назначенного элемента является последним индексом, назначенным оператором, плюс один.

manatwork
источник
Полезно добавить: неинициализированные элементы будут расширяться до 0 в арифметических расширениях и "" в других расширениях.
Цифровая травма
2

Распечатать первое слово в строке

Если строка находится в переменной aи не содержит escape-символов \и символов формата ( и %), используйте это:

printf $a

Но он будет длиннее следующего кода, если необходимо сохранить результат в переменную вместо печати:

x=($a)
$x
jimmy23013
источник
1

Делаем 2 встраиваемых цикла с 1 forинструкцией:

for ((l=i=0;l<=99;i=i>98?l++,0:++i)) ;do
    printf "I: %2d, L: %2d\n" $i $l
done |
    tee >(wc) | (head -n4;echo ...;tail -n 5)
I:  0, L:  0
I:  1, L:  0
I:  2, L:  0
I:  3, L:  0
...
I: 96, L: 99
I: 97, L: 99
I: 98, L: 99
I: 99, L: 99
  10000   40000  130000
Ф. Хаури
источник
1

Назначать и печатать строки в кавычках

Если вы хотите присвоить строку в кавычках переменной, а затем вывести значение этой переменной, то обычным способом сделать это будет:

a="Programming Puzzles & Code Golf";echo $a

Если aранее был не установлен, это может быть сокращено до:

echo ${a=Programming Puzzles & Code Golf}

Если aранее был установлен, то это следует использовать вместо:

echo ${a+Programming Puzzles & Code Golf}

Обратите внимание, что это полезно, только если строка требует кавычек (например, содержит пробел). Без кавычек, a=123;echo $aэто так же коротко.

Цифровая травма
источник
${a+foo}не устанавливается a.
GammaFunction