Як використовувати подвійні або одинарні дужки, дужки, фігурні дужки


657

Мене бентежить використання дужок, круглих дужок, фігурних дужок у Bash, а також різниця між їх подвійною чи одиничною формами. Чи є чітке пояснення?

Відповіді:


605

У Баша є testі [оболонки.

Подвійний кронштейн , який є оболонкою ключового слова, дає додаткові функціональні можливості . Наприклад, ви можете використовувати &&і ||замість -aі -oі є регулярний оператор виразами =~.

Крім того, у простому тесті подвійні квадратні дужки, здається, оцінюють набагато швидше, ніж одиничні.

$ time for ((i=0; i<10000000; i++)); do [[ "$i" = 1000 ]]; done

real    0m24.548s
user    0m24.337s
sys 0m0.036s
$ time for ((i=0; i<10000000; i++)); do [ "$i" = 1000 ]; done

real    0m33.478s
user    0m33.478s
sys 0m0.000s

Дужки, крім обмеження назви змінної, використовуються для розширення параметрів, щоб ви могли робити такі дії:

  • Обрізати вміст змінної

    $ var="abcde"; echo ${var%d*}
    abc
  • Зробіть заміни подібними до sed

    $ var="abcde"; echo ${var/de/12}
    abc12
  • Використовуйте значення за замовчуванням

    $ default="hello"; unset var; echo ${var:-$default}
    hello
  • та ще кілька

Крім того, розширення дужок створюють списки рядків, які зазвичай повторюються в циклі:

$ echo f{oo,ee,a}d
food feed fad

$ mv error.log{,.OLD}
(error.log is renamed to error.log.OLD because the brace expression
expands to "mv error.log error.log.OLD")

$ for num in {000..2}; do echo "$num"; done
000
001
002

$ echo {00..8..2}
00 02 04 06 08

$ echo {D..T..4}
D H L P T

Зауважте, що до Bash 4 не було доступно провідних функцій нуля та приросту.

Дякую gboffi, що нагадав про розширення підтяжок.

Подвійні дужки використовуються для арифметичних операцій :

((a++))

((meaning = 42))

for ((i=0; i<10; i++))

echo $((a + b + (14 * c)))

і вони дозволяють опустити знаки долара на цілі і масивні змінні та включати пробіли навколо операторів для читабельності.

Одні дужки також використовуються для індексів масиву :

array[4]="hello"

element=${array[index]}

Фігурна дужка потрібна для (більшості / всіх?) Посилань на масив праворуч.

коментар ephemient нагадав мені, що круглі дужки також використовуються для допоміжних оболонок . І що вони використовуються для створення масивів.

array=(1 2 3)
echo ${array[1]}
2

8
ПОПЕРЕДЖЕННЯ. Ця функція є вилковою бомбою, не запускайте її. Див.: En.wikipedia.org/wiki/Fork_bomb
Призупинено до подальшого повідомлення.

3
Це лише вилка бомба, якщо викликати її додатково :.
ефеміент

7
Також для повноти я щойно натрапив на це за старим сценарієм $[expression]:; це старий, застарілий арифметичний синтаксис виразів для новішого, кращого синтаксису:$((expression))
michael

2
@DennisWilliamson Ще одним використанням фігурних брекетів bashє створення послідовностей, як зазначено периферійно нижче ( stackoverflow.com/a/8552128/2749397 ) Як я хотів би трохи прокоментувати цю функцію (як ви цього не згадали ;-) Я " m, маючи на увазі використання найбільш проголошеної відповіді як транспортного засобу ... Два приклади буквальної послідовності: echo {01..12}-> 01 02 03 04 05 06 07 08 09 10 11 12(зверніть увагу на початковий нуль); echo {C..Q}-> C D E F G H I J K L M N O P Q. Основне його використання - петлі, наприклад, for cnt in {01..12} ; do ... ${cnt} ... ; done
gboffi

1
@gboffi: Функція прокладки з нулем стала доступною у Bash 4. Також у Bash 4 можна вказати приріст у послідовності: echo {01..12..2}-> "01 03 05 07 09 11". Дякуємо за нагадування про послідовності. Я додам це до своєї відповіді.
Призупинено до подальшого повідомлення.

335
  1. Одинарна дужка ( [) зазвичай насправді викликає програму з назвою [; man testабо man [для отримання додаткової інформації. Приклад:

    $ VARIABLE=abcdef
    $ if [ $VARIABLE == abcdef ] ; then echo yes ; else echo no ; fi
    yes
  2. Подвійна дужка ( [[) робить те ж саме (в основному), як і одна дужка, але є вбудованим басом.

    $ VARIABLE=abcdef
    $ if [[ $VARIABLE == 123456 ]] ; then echo yes ; else echo no ; fi
    no
  3. Параметри ( ()) використовуються для створення підшаровок. Наприклад:

    $ pwd
    /home/user 
    $ (cd /tmp; pwd)
    /tmp
    $ pwd
    /home/user

    Як бачимо, підсфера дозволяє вам виконувати операції, не впливаючи на оточення поточної оболонки.

  4. (a) Дужки ( {}) використовуються для однозначної ідентифікації змінних. Приклад:

    $ VARIABLE=abcdef
    $ echo Variable: $VARIABLE
    Variable: abcdef
    $ echo Variable: $VARIABLE123456
    Variable:
    $ echo Variable: ${VARIABLE}123456
    Variable: abcdef123456

    (b) Дужки також використовуються для виконання послідовності команд у поточному контексті оболонки, наприклад

    $ { date; top -b -n1 | head ; } >logfile 
    # 'date' and 'top' output are concatenated, 
    # could be useful sometimes to hunt for a top loader )
    
    $ { date; make 2>&1; date; } | tee logfile
    # now we can calculate the duration of a build from the logfile

Існує тонка синтаксична різниця ( ), хоча (див. Посилання на bash ); по суті, точка з коми ;після останньої команди в фігурних дужках є обов'язковою, а фігурні дужки {, } повинні бути оточені пробілами.


26
Ну, [насправді вбудований в Bash, але він повинен діяти так, /bin/[як на відміну від [[вбудованого. [[має різні функції, як більш логічні операції та різні котирування ролей. Додатково: окремі дужки також використовуються для масивів, заміщення процесів та розширених глобусів; подвійні дужки використовуються для арифметики; фігурні дужки {}використовуються для групування команд або безлічі типів розширення параметрів або розширення дужок або розширення послідовностей. Я впевнений, що я пропустив і деякі інші вживання ...
ефемія

4
Подвійне дорівнювання в виразі if [ $VARIABLE == abcdef ]- це башизм, якого, хоча це працює, - можливо, слід уникати; або явно використовуйте bash ( if [[ ...==...]]), або дайте зрозуміти, що ви використовуєте більш традиційний умовний ( if [ "$VARIABLE" = "abcdef" ]). Імовірно, сценарії повинні починатися максимально просто і портативно, до тих пір, поки вони дійсно не потребують функцій, характерних для bash (з тих чи інших причин). Але в будь-якому випадку, наміри повинні бути зрозумілими; "=" і "==" і "[[" і "[" працюють по-різному, і їх використання повинно бути послідовним.
Майкл

3
@michael_n: +1 за це зауваження. На стороні записки, я люблю сценарії, але я знаходжу це досить незручно , що портативний шлях до випробування через [ "$var" = ".."]замість ==, в той час як в C було б призначити замість тестування (і досить часта причина помилок) ... чому Didn не testвикористовувати ==замість =? хтось знає?
Олів'є Дулак

Також ось дивна річ, що (принаймні, на Kubuntu) команда /usr/bin/[не є символьним посиланням на /usr/bin/test, і багато іншого: ці програми навіть мають кілька різних розмірів!
Привіт-Ангел

Крім того: одна дужка, що закривається, )є частиною caseсинтаксису оператора для закінчення рядка справи. У ньому немає скобок, що відкриваються. Це відкинуло мене з першого разу, коли я це побачив.
Агустін Аменабар

302

Кронштейни

if [ CONDITION ]    Test construct  
if [[ CONDITION ]]  Extended test construct  
Array[1]=element1   Array initialization  
[a-z]               Range of characters within a Regular Expression
$[ expression ]     A non-standard & obsolete version of $(( expression )) [1]

[1] http://wiki.bash-hackers.org/scripting/obsolete

Фігурні дужки

${variable}                             Parameter substitution  
${!variable}                            Indirect variable reference  
{ command1; command2; . . . commandN; } Block of code  
{string1,string2,string3,...}           Brace expansion  
{a..z}                                  Extended brace expansion  
{}                                      Text replacement, after find and xargs

Круглі дужки

( command1; command2 )             Command group executed within a subshell  
Array=(element1 element2 element3) Array initialization  
result=$(COMMAND)                  Command substitution, new style  
>(COMMAND)                         Process substitution  
<(COMMAND)                         Process substitution 

Подвійні дужки

(( var = 78 ))            Integer arithmetic   
var=$(( 20 + 5 ))         Integer arithmetic, with variable assignment   
(( var++ ))               C-style variable increment   
(( var-- ))               C-style variable decrement   
(( var0 = var1<98?9:21 )) C-style ternary operation

@Yola, чи можете ви поясніть, що саме означає $ (varname)? У проектах Apple Xcode я можу вказати шляхи до файлів як сценарій введення / виводу. якщо я вказую $ SRC_ROOT / myFile.txt або $ {SRC_ROOT} /myFile.txt (varCRC_ROOT експортується системою збірки) - не працює. працює лише $ (SRC_ROOT) /myFile.txt. Що може бути причиною? явно var ім'я не команда?
Motti Shneor

1
@MottiShneor, у вашому випадку $(varname)не має відношення до синтаксису bash. Це частина синтаксису Makefile .
Сашко

Не так - Xcode не будується за допомогою makefile, а його змінні є змінними середовища. Власні процеси побудови системи Xcode зчитують значення цих заздалегідь визначених змінних середовища. Крок користувацької збірки - це лише звичайні сценарії оболонки (bash чи інші) і мають доступ до тих же варіантів.
Мотті Шноор

@MottiShneor, добре, давайте уточнимо: швидше за все, це частина синтаксису xcconfig . У будь-якому випадку $(varname)не має відношення до синтаксису bash у вашому випадку.
Сашко

Ви не згадуєте, у чому різниця між тестовою конструкцією та розширеною конструкцією тесту.
Нікос

23

Я просто хотів додати їх із TLDP :

~:$ echo $SHELL
/bin/bash

~:$ echo ${#SHELL}
9

~:$ ARRAY=(one two three)

~:$ echo ${#ARRAY}
3

~:$ echo ${TEST:-test}
test

~:$ echo $TEST


~:$ export TEST=a_string

~:$ echo ${TEST:-test}
a_string

~:$ echo ${TEST2:-$TEST}
a_string

~:$ echo $TEST2


~:$ echo ${TEST2:=$TEST}
a_string

~:$ echo $TEST2
a_string

~:$ export STRING="thisisaverylongname"

~:$ echo ${STRING:4}
isaverylongname

~:$ echo ${STRING:6:5}
avery

~:$ echo ${ARRAY[*]}
one two one three one four

~:$ echo ${ARRAY[*]#one}
two three four

~:$ echo ${ARRAY[*]#t}
one wo one hree one four

~:$ echo ${ARRAY[*]#t*}
one wo one hree one four

~:$ echo ${ARRAY[*]##t*}
one one one four

~:$ echo $STRING
thisisaverylongname

~:$ echo ${STRING%name}
thisisaverylong

~:$ echo ${STRING/name/string}
thisisaverylongstring

18
Розум, який echo ${#ARRAY}відображає три, тому що перший елемент ARRAYмістить три символи, а не тому, що він містить три елементи! Для друку використовуйте кількість елементів echo ${#ARRAY[@]}.
TrueY

@zeal ${TEST:-test}дорівнює, $TESTякщо змінна TESTіснує, інакше вона просто повертає рядок "test". Є ще одна версія, яка робить ще більше: ${TEST:=test}--- яка також дорівнює, $TESTякщо TEST існує, але коли це не відбувається, вона створює змінну TESTі присвоює значення "test", а також стає значенням всього виразу.
Любить ймовірність

18

Різниця між тестом , [ та [[ пояснюється докладно в BashFAQ .

Щоб скоротити довгу історію: тест реалізує старий, портативний синтаксис команди. Майже у всіх оболонках (виняток становлять найдавніші снаряди Борна) [є синонімом тесту (але вимагає остаточного аргументу]). Незважаючи на те, що всі сучасні оболонки мають вбудовані реалізації [, зазвичай все ще є зовнішній виконуваний файл з таким ім'ям, наприклад / bin / [.

[[це нова вдосконалена його версія, яка є ключовим словом, а не програмою. Це сприятливо впливає на простоту використання, як показано нижче. [[розуміється KornShell та BASH (наприклад, 2.03), але не старішими POSIX або BourneShell.

І висновок:

Коли слід використовувати нову тестову команду [[і коли стару [? Якщо портативність до BourneShell викликає занепокоєння, слід використовувати старий синтаксис. Якщо, з іншого боку, сценарій вимагає BASH або KornShell, новий синтаксис набагато гнучкіший.


18

Дужки у визначенні функції

Для ()визначення функції використовуються дужки :

function_name () { command1 ; command2 ; }

Ось чому вам доведеться уникати дужок навіть у параметрах команди:

$ echo (
bash: syntax error near unexpected token `newline'

$ echo \(
(

$ echo () { command echo The command echo was redefined. ; }
$ echo anything
The command echo was redefined.

О, я спробував на csh. Моє ліжко. Коли я пробую баш, він працює. Я не знав команди "команда" bash.
Чан Кім

як я можу скасувати переосмислення команди echo ()? (без повторного відкриття басу)
Чан Кім

2
@ChanKim: unset -f echo. Див help unset.
пабук

0
Truncate the contents of a variable

$ var="abcde"; echo ${var%d*}
abc

Make substitutions similar to sed

$ var="abcde"; echo ${var/de/12}
abc12

Use a default value

$ default="hello"; unset var; echo ${var:-$default}
hello

Коли ви відповідаєте на запитання, не прагніть лише до "коду", але також спробуйте додати пояснення ...
Mikev
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.