Какие общие советы у вас есть для игры в гольф в Баше? Я ищу идеи, которые могут быть применены к кодовым проблемам гольфа в целом, которые, по крайней мере, несколько специфичны для Bash (например, «удалить комментарии» - это не ответ). Пожалуйста, оставьте один совет за ответ.
55
sh
и какая оболочка допускает этотfor
синтаксис? это прямо разрешено вzsh
.sh
и что Bash также позволяет это, хотя, к сожалению, у меня нет цитаты.csh
наверное - так они работали в этой оболочке.ksh93
вышеупомянутой вещи может быть:,;{1..10}
а вbash
:printf %s\\n {1..10}
for((;i++<10)){ echo $i;}
корочеfor i in {1..10};{ echo $i;}
Для арифметического расширения используйте
$[…]
вместо$((…))
:В арифметических расширениях не используйте
$
:Арифметическое расширение выполняется для индексов индексированных массивов, поэтому не используйте их
$
там:В арифметических расширениях не используйте
${…}
:источник
while((i--))
, которая работает, сwhile[i--]
илиwhile $[i--]
не работает для меня. GNU bash, версия 4.3.46 (1)y=`bc<<<"($x*2.2)%10/1"`
... пример использованияbc
для нецелочисленных вычислений ... обратите внимание, что/1
в конце усечение результирующего десятичного числа до целого .s=$((i%2>0?s+x:s+y))
... пример использования тернарного оператора в арифметике bash. Это корочеif..then..else
или[ ] && ||
GNU bash, version 5.0.2(1)-release (x86_64-apple-darwin16.7.0)
и это не в моем.Нормальный, длинный и скучный способ определения функции
Как выяснил этот парень , вам обязательно нужно пробел до
CODE
и точка с запятой после него.Это небольшой трюк, который я узнал от @DigitalTrauma :
Это на два символа короче, и это работает так же хорошо, при условии, что вам не нужно переносить какие-либо изменения в значения переменных после возврата функции ( скобки запускают тело в подоболочке ).
Как указывает @ jimmy23013 в комментариях, даже скобки могут быть ненужными.
В Руководстве Bash Reference показывает , что функции могут быть определены следующим образом :
Команда соединения может быть:
until
,while
илиfor
if
,case
,((...))
или[[...]]
(...)
или{...}
Это означает, что все следующие условия действительны:
И я использовал фигурные скобки, как присоски ...
источник
f()while ...
f()if ...
и другие составные команды.f()CODE
это законно. Оказывается, чтоf()echo hi
это разрешено в pdksh и zsh, но не в bash.for
так как по умолчанию он позиционируется:f()for x do : $x; done;set -x *;PS4=$* f "$@"
или что-то еще.:
это команда, которая ничего не делает, ее состояние выхода всегда успешно, поэтому ее можно использовать вместоtrue
.источник
:(){:|:}
Больше советов
Злоупотреблять троичным оператором
((test)) && cmd1 || cmd2
или[ test ] && cmd1 || cmd2
, насколько это возможно.Примеры (длина отсчета всегда исключает верхнюю строку):
Используя только троичные операторы, это можно легко сократить до:
Как отметили в комментариях nyuszika7h, этот конкретный пример может быть сокращен еще больше, используя
case
:Кроме того, предпочитайте скобки как можно больше скобок. Поскольку круглые скобки являются метасимволами, а не словом, они никогда не требуют пробелов в любом контексте. Это также означает запуск максимально возможного количества команд в подоболочке, потому что фигурные скобки (то есть
{
и}
) являются зарезервированными словами, а не метасимволами, и поэтому для правильного синтаксического анализа должны иметь пробелы с обеих сторон, а метасимволы - нет. Я предполагаю, что вы уже знаете, что подоболочки не влияют на родительскую среду, поэтому, предполагая, что все примеры команд могут безопасно выполняться в подоболочке (что не типично в любом случае), вы можете сократить приведенный выше код до этой :Кроме того, если вы не можете, использование скобок все еще может минимизировать его. Следует иметь в виду, что он работает только для целых чисел, что делает его бесполезным для целей этого примера (но это намного лучше, чем
-eq
для целых чисел).Еще одна вещь, избегайте кавычек, где это возможно. Используя приведенный выше совет, вы можете в дальнейшем его минимизировать. Пример:
В условиях тестирования предпочитайте одинарные скобки двойным скобкам, насколько это возможно, за некоторыми исключениями. Он отбрасывает два символа бесплатно, но в некоторых случаях он не так надежен (это расширение Bash - см. Пример ниже). Кроме того, используйте единственный аргумент равенства, а не двойной. Это свободный персонаж, чтобы бросить.
Обратите внимание на это предостережение, особенно при проверке нулевого вывода или неопределенной переменной:
Во всех технических аспектах этот конкретный пример был бы лучше всего с
case
...in
:Итак, мораль этого поста такова:
if
/if-else
/ etc. конструкты.case
...in
, так как это может сэкономить немало байтов, особенно при сопоставлении строк.PS: Вот список метасимволов, распознаваемых в Bash независимо от контекста (и может разделять слова):
РЕДАКТИРОВАТЬ: Как указал manatwork, тест с двойными скобками работает только для целых чисел. Кроме того, косвенно, я обнаружил, что вам нужно иметь пробел вокруг
==
оператора. Исправил мой пост выше.Мне также было лень пересчитывать длину каждого сегмента, поэтому я просто удалил их. Это должно быть достаточно легко найти онлайн калькулятор длины строки, если это необходимо.
источник
[ $t=="hi" ]
всегда будет иметь значение 0, поскольку оно анализируется как[ -n "STRING" ]
.(($t=="hi"))
всегда будет иметь значение 0, пока $ t имеет нечисловое значение, поскольку строки арифметических вычислений приводятся к целым числам. Некоторые тестовые случаи: pastebin.com/WefDzWbLcase
будет короче. Кроме того, вам не нужно место до}
, но вы делаете после{
.=
быть менее надежным, чем==
?=
поручено POSIX,==
нет.Вместо того
grep -E
,grep -F
,grep -r
, использованиеegrep
,fgrep
,rgrep
, экономия двух символов. Более короткие устарели, но работают нормально.(Вы просили один совет за ответ!)
источник
Pgrep
дляgrep -P
. Хотя я вижу, как это можно легко спутать с темpgrep
, что используется для поиска процессов.grep -o
многоДоступ к элементу 0 массива возможен только с именем переменной, пятибайтовая экономия по сравнению с явным указанием индекса 0:
источник
Если вам нужно передать содержимое переменной в STDIN следующего процесса в конвейере, обычно выводить переменную в конвейер. Но вы можете добиться того же с помощью
<<<
строки bash здесь :источник
s=code\ golf
,echo $s|
и<<<$s
(имея в виду , что последние две работы только потому , что есть не повторяющиеся пробелы и т.д.).Избегайте
$( ...command... )
, есть альтернатива, которая сохраняет один символ и делает то же самое:источник
$( )
требуется, если у вас есть вложенные подстановки команд; в противном случае вам придется бежать изнутри``
$()
когда я хотел, например, выполнить замену на своем компьютере вместоscp
целевого. В большинстве случаев они идентичны.$()
может сделать, если вы правильно цитируете вещи. (если вам не нужна ваша команда, чтобы пережить что-то, что бросается в глаза,$
но не отступает ). Есть некоторые тонкие различия в цитировании вещей внутри них. mywiki.wooledge.org/BashFAQ/082 объясняет некоторые различия. Если вы не играете в гольф, никогда не используйте спины.echo `bc <<<"\`date +%s\`-12"`
... (Сложно опубликовать образец, содержащий обратные пометки в комментариях, там!)Используйте
if
для группировки командПо сравнению с этим советом, который
if
вообще удаляет , это должно работать лучше только в некоторых очень редких случаях, например, когда вам нужны возвращаемые значения изif
.Если у вас есть группа команд, оканчивающаяся на
if
:if
Вместо этого вы можете заключить команды в условие:Или если ваша функция заканчивается на
if
:Вы можете удалить брекеты:
источник
[test] && $if_true || $else
в этих функциях и сохранить несколько байтов.&&
и||
Используйте арифметику
(( ... ))
для условийВы можете заменить:
по
(Примечание: после этого места нет
if
)или даже
... или если только одна команда
Далее: Скрыть настройку переменной в арифметической конструкции:
или то же самое
... где, если i> 5, то c = 1 (не 0;)
источник
[ ]
вместо(())
.[ ]
тобой нужен знак доллара для переменной. Я не вижу, как вы могли бы сделать то же самое с такой же или меньшей длиной, используя[ ]
.((...))
новой строки или пробела не требуется. Например,for((;10>n++;)){((n%3))&&echo $n;}
попробуйте онлайн!Более короткий синтаксис для бесконечных циклов (который может быть экранирован с помощью операторов
break
илиexit
)Это короче
while true;
иwhile :;
.Если вам не нужен
break
(exit
единственный способ уйти), вы можете вместо этого использовать рекурсивную функцию.Если вам нужен break, но вам не нужен выход и вам не нужно переносить какие-либо изменения переменных вне цикла, вы можете использовать рекурсивную функцию с круглыми скобками вокруг тела , которая запускает тело функции в подоболочке.
источник
Однолинейные
for
петлиАрифметическое выражение, объединенное с расширением диапазона, будет оцениваться для каждого элемента в диапазоне. Например следующее:
будет оценивать
expression
10 раз.Это часто значительно короче, чем эквивалентный
for
цикл:Если вы не возражаете, команда не обнаружила ошибки, вы можете удалить начальный
:
. Для итераций, превышающих 10, вы также можете использовать диапазоны символов, например,{A..z}
будет повторяться 58 раз.В качестве практического примера, следующие оба производят первые 50 треугольных чисел, каждое в своей строке:
источник
for((;0<i--;)){ f;}
Зацикливаться на аргументах
Как отмечалось в цикле «for» Bash без части «in foo bar…» , вход
in "$@;"
infor x in "$@;"
избыточен.От
help for
:Например, если мы хотим привести в квадрат все числа с заданными позиционными аргументами в Bash-скрипте или функции, мы можем сделать это.
Попробуйте онлайн!
источник
Альтернатива кошке
Скажем, вы пытаетесь прочитать файл и использовать его в другом месте. Что вы можете сделать, это:
Если бы содержимое
bar
былоfoobar
, это напечатало быfoo foobar
.Однако есть альтернатива, если вы используете этот метод, который экономит 3 байта:
источник
<bar
само по себе это не работает, но размещение его в кавычках работает?<
помещает файл в команду, но в этом случае она выводит его в стандартный вывод из-за причуды. Обратные оценки оценивают это вместе.`cat`
?Используйте
[
вместо[[
иtest
когда это возможноПример:
Используйте
=
вместо==
для сравненияПример:
Обратите внимание, что вы должны иметь пробелы вокруг знака равенства, иначе это не сработает. То же относится и к
==
основанным на моих тестах.источник
[
Против[[
может зависеть от количества требуемых котировок: pastebin.com/UPAGWbDQ[
...]
==/bin/test
, но[[
...]]
! =/bin/test
И никогда не следует отдавать предпочтение[
...]
более[[
...]]
вне CodegolfАльтернативы
head
line
на три байта корочеhead -1
, но считается устаревшим .sed q
на два байта корочеhead -1
.sed 9q
на один байт корочеhead -9
.источник
line
от Util-Linux пакета читать одну строку.tr -cd
короче чемgrep -o
Например, если вам нужно сосчитать пробелы,
grep -o <char>
(вывести только совпадающее) дает 10 байт, аtr -cd <char>
(удалить дополнение<char>
) - 9.( источник )
Обратите внимание, что они оба дают немного разные результаты.
grep -o
возвращает результаты, разделенные строкой, в то время какtr -cd
выдает их все в одной строке, поэтомуtr
не всегда может быть благоприятным.источник
Сократить имена файлов
В недавнем испытании я пытался прочитать файл
/sys/class/power_supply/BAT1/capacity
, однако его можно сократить, так/*/*/*/*/capac*y
как другого файла с таким форматом не существует.Например, если у вас был каталог,
foo/
содержащий файлы,foo, bar, foobar, barfoo
и вы хотели сослаться на файлfoo/barfoo
, вы можете использовать егоfoo/barf*
для сохранения байта.*
Представляет собой «ничего», и эквивалентен регулярное выражение.*
.источник
Используйте канал для
:
команды вместо/dev/null
.:
Встроенный съест все его вход.источник
echo a|tee /dev/stderr|:
не будет ничего печатать.echo a|tee /dev/stderr|:
напечатал на моем компьютере, но в другом месте SIGPIPE может убить тебя первым. Это может зависеть от версииtee
.tee >(:) < <(seq 1 10)
будет работать, ноtee /dev/stderr | :
не будет. Дажеa() { :;};tee /dev/stderr < <(seq 1 10)| a
ничего не печатать.:
внутренняя сущность совсем не ест ... если вы допустите ввод двоеточия, вы можете залить канал в ошибку 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)
split
имеет другой (устарел, но никого не волнует) синтаксис для разделения ввода на разделыN
строк каждый: вместоsplit -lN
вы можете использоватьsplit -N
напримерsplit -9
.источник
Развернуть тесты
По сути, оболочка - это своего рода макроязык, или, по крайней мере, гибрид или какой-то еще. Каждая командная строка может быть в основном разбита на две части: часть анализа / ввода и часть расширения / вывода.
Первая часть - это то, на чем фокусируется большинство людей, потому что она самая простая: вы видите, что получаете. Вторая часть - это то, что многие избегают даже когда-либо пытаться понять очень хорошо, и именно поэтому люди говорят, что подобные вещи
eval
являются злом, и всегда цитируют ваши расширения - люди хотят, чтобы результат первой части был равен первому. Это нормально - но это приводит к излишне длинным ветвям кода и множеству посторонних тестов.Расширения проходят самотестирование . Эти
${param[[:]#%+-=?]word}
формы более чем достаточно , чтобы проверить содержимое параметра, являются вложенностью, и все они основаны вокруг оценки для NUL - которая является то , что большинство людей ожидают тестов в любом случае.+
особенно удобно в циклах:... в то время как
read
тянет в не пустые строки"${r:+set}"
расширяется"set"
и позиционирование$r
добавляется. Но когда пустая строкаread
,$r
пустой и"${r:+set}"
расширяется""
- что является неправильной командой. Но так как командная строка расширяется до""
того ищется команда нуля,"${r:=$*}"
принимают значения всех positionals сцепленной на первые байтах в$IFS
а.r()
может быть вызван снова в|{
составной команде;}
с другим значением для того,$IFS
чтобы получить также следующий входной абзац, так как для оболочки запрещеноread
буферизовать после следующей\n
строки в вводе.источник
Используйте хвостовую рекурсию, чтобы сделать петли короче:
Они эквивалентны в поведении (хотя, вероятно, не в использовании памяти / PID):
И это примерно эквивалентно:
(технически последние три всегда выполнят тело хотя бы один раз)
Использование
$0
требует, чтобы ваш скрипт находился в файле, а не вставлялся в приглашение bash.В конечном итоге ваш стек может переполниться, но вы сохраните несколько байтов.
источник
Иногда короче использовать
expr
встроенную функцию для отображения результата простого арифметического выражения вместо обычногоecho $[ ]
. Например:на один байт короче, чем:
источник
Используйте
pwd
вместо того,echo
чтобы генерировать строку выводаНужно поместить строку в стандартный вывод, но не заботиться о содержимом и хотите ограничить свой ответ встроенными командами оболочки?
pwd
Байт короче, чемecho
.источник
Кавычки могут быть опущены при печати строк.
Выход в SM-T335 LTE, Android 5.1.1:
источник
При назначении элементов непрерывного массива вы все равно можете пропустить последовательные индексы непрерывных блоков:
Результат тот же:
По словам
man bash
:источник
Распечатать первое слово в строке
Если строка находится в переменной
a
и не содержит escape-символов\
и символов формата ( и%
), используйте это:Но он будет длиннее следующего кода, если необходимо сохранить результат в переменную вместо печати:
источник
Делаем 2 встраиваемых цикла с 1
for
инструкцией:источник
Назначать и печатать строки в кавычках
Если вы хотите присвоить строку в кавычках переменной, а затем вывести значение этой переменной, то обычным способом сделать это будет:
Если
a
ранее был не установлен, это может быть сокращено до:Если
a
ранее был установлен, то это следует использовать вместо:Обратите внимание, что это полезно, только если строка требует кавычек (например, содержит пробел). Без кавычек,
a=123;echo $a
это так же коротко.источник
${a+foo}
не устанавливаетсяa
.