Поради щодо гольфу в Баші


55

Які загальні поради щодо гольфу в Баші? Я шукаю ідеї, які можна застосувати до проблем із гольфом взагалі, які принаймні дещо характерні для Баша (наприклад, "видалити коментарі" - це не відповідь). Будь ласка, опублікуйте одну пораду за кожну відповідь.

Відповіді:


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

Заміна while((i--)), яка працює, на мене while[i--]чи while $[i--]не працювала. GNU bash, версія 4.3.46 (1)
Glenn Randers-Pehrson

1
Правильно, @ GlennRanders-Pehrson. Це не повинно працювати.
манатурка

y=`bc<<<"($x*2.2)%10/1"`... приклад використання bcдля не цілих обчислень ... зверніть увагу /1на кінець урізає отриманий десятковий знак у цілий.
roblogic

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 Manual показує , що функції можуть бути визначені наступним чином :

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/ тощо. конструкти.
  2. Використовуйте круглі дужки якомога більше і виконайте якомога більше сегментів у підшарах, оскільки дужки є метасимволами, а не зарезервованими словами.
  3. Уникайте цитат максимально фізично.
  4. Перевірте case... in, оскільки це може зберегти досить багато байтів, особливо при збігу рядків.

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

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

EDIT: Як було вказано на маніпуляції, тест подвійних дужок працює лише для цілих чисел. Також опосередковано я виявив, що вам потрібно мати пробіли навколо ==оператора. Виправлена ​​моя публікація вище.

Я також був лінивий, щоб перерахувати довжину кожного сегмента, тому просто видалив їх. Якщо це необхідно, знайти онлайн-калькулятор довжини рядків досить просто.


Вибачте, але у вас є серйозні помилки. [ $t=="hi" ]завжди буде оцінювати до 0, як це аналізується як [ -n "STRING" ]. (($t=="hi"))завжди буде оцінювати до 0 до тих пір, поки $ t має нечислове значення, оскільки рядки вимушені в цілі числа в арифметичних оцінках. Деякі тестові випадки: pastebin.com/WefDzWbL
манатура

@manatwork Дякую за улов. Я відповідно оновлю.
Ісія Медоуз

Тут використовується caseкоротше. Крім того, вам не потрібен пробіл раніше }, але ви робите після {.
nyuszika7h

1
Чому було =б менш надійним, ніж ==? =призначено POSIX, ==чи не так.
Денніс

1
Питання вимагає однієї поради на відповідь ...
Toby Speight

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 тут string :

$ 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.

Якщо у вас є командна група, яка закінчується символом a 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

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

Якщо вам потрібен перерва, але вам не потрібен вихід, і вам не потрібно переносити будь-яку змінну модифікацію поза циклом, ви можете використовувати рекурсивну функцію з дужками по всьому тілу , які запускають функціональне тіло в підрозділі.

f()(code;f);f

6

Однорядкові forпетлі

Арифметичний вираз, з'єднаний з розширенням діапазону, буде оцінено для кожного елемента в діапазоні. Наприклад, наступне:

: $[expression]{0..9}

оцінюватимуть expression10 разів.

Це часто значно коротше, ніж еквівалентний forцикл:

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

Якщо ви не заперечуєте, щоб команда не знайшла помилок, ви можете видалити inital :. Для ітерацій, більших за 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;}
roblogic

5

Переведіть аргументи на цикл

Як наголошується в Bash «для» петлі без «в Foo барі ...» частини , то 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`

1
Чи є причина, чому <barсама по собі не працює, а розміщення її в задній план робить?
Kritixi Lithos

@Cowsquack Так. <Поміщає файл в команду, але в цьому випадку він поміщає його в стандартний висновок завдяки капризу. Повернення оцінюють це разом.
Okx

Чи існує коротший спосіб зчитувати зі стандартного вводу, крім `cat`?
Джоель

4

Використовуйте [замість [[і testколи це можливо

Приклад:

[ -n $x ]


Використовуйте =замість ==порівняння

Приклад:

[ $x = y ]

Зверніть увагу, що ви повинні мати пробіли навколо знака рівності, інакше це не працюватиме. Те саме стосується ==моїх тестів.


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 пакету читати один рядок.
манатура

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може не завжди бути сприятливим.


4

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

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

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

*Являє собою «нічого», і еквівалентний регулярний вираз .*.


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 для моєї компетенції ... у будь-якому випадку, :внутрішня їжа зовсім не їсть ... якщо ви додасте введення в товсту кишку, ви можете залити трубку помилкою ... але ви можете плавати перенаправлення двокрапкою чи киньте процес із нею ... :| 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:=$*}"приймає також значення всіх позицій, об'єднаних у перший байт $IFS. r()може бути викликаний ще раз у |{складеній команді ;}w / інше значення для $IFSотримання наступного вхідного абзацу, оскільки це незаконно readбуферизація оболонки за межами наступної \nлінії введення.


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щоб генерувати рядок виводу

Потрібно поставити рядок на stdout, але не піклуватися про вміст, і хочете обмежити свою відповідь на вбудовані оболонки? 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:

Масиви призначаються за допомогою складених призначень найменування форми = (значення 1 ... значення n ), де кожне значення має форму [ підпис ) = рядок . Присвоєння індексованого масиву не вимагає нічого, крім рядка . При призначенні індексованих масивів, якщо постачаються необов'язкові дужки та індекс, цей індекс присвоюється; в іншому випадку індекс призначеного елемента - це останній індекс, призначений випискою плюс один.


Корисно додати: неініціалізовані елементи розширяться до 0 в арифметичних розширеннях та "" в інших розширеннях.
Цифрова травма

2

Надрукуйте перше слово рядком

Якщо рядок знаходиться в змінній aі не містить символів втечі та форматування ( \і %), використовуйте це:

printf $a

Але це буде довше, ніж наступний код, якщо це потрібно для збереження результату в змінну замість друку:

x=($a)
$x

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.