Jak używać nawiasów podwójnych lub pojedynczych, nawiasów, nawiasów klamrowych

657

Jestem zdezorientowany używaniem nawiasów, nawiasów, nawiasów klamrowych w Bash, a także różnicą między ich podwójnymi lub pojedynczymi formami. Czy jest jasne wytłumaczenie?

Tim
źródło

Odpowiedzi:

605

W Basha, testi [są powłoki builtins.

Podwójny uchwyt , który jest powłoką Hasło umożliwia dodatkową funkcjonalność. Na przykład, można użyć &&i ||zamiast -aa -oi tam regularne operator dopasowanie wyraz =~.

Ponadto w prostym teście nawiasy kwadratowe wydają się oceniać znacznie szybciej niż pojedyncze.

$ 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

Nawiasy klamrowe oprócz ograniczania nazwy zmiennej służą do rozszerzania parametrów, dzięki czemu można wykonywać następujące czynności:

  • Obetnij zawartość zmiennej

    $ var="abcde"; echo ${var%d*}
    abc
  • Dokonaj podstawień podobnych do sed

    $ var="abcde"; echo ${var/de/12}
    abc12
  • Użyj wartości domyślnej

    $ default="hello"; unset var; echo ${var:-$default}
    hello
  • i kilka innych

Ponadto rozszerzenia nawiasów tworzą listy ciągów, które są zazwyczaj iterowane w pętlach:

$ 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

Pamiętaj, że wiodące funkcje zerowania i przyrostu nie były dostępne przed Bash 4.

Dzięki gboffi za przypomnienie mi o rozszerzeniach aparatu.

Podwójne nawiasy są używane do operacji arytmetycznych :

((a++))

((meaning = 42))

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

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

i pozwalają ominąć znaki dolara na zmiennych całkowitych i tablicowych oraz zawierać spacje wokół operatorów dla czytelności.

Pojedyncze nawiasy klamrowe są również używane dla indeksów tablicowych :

array[4]="hello"

element=${array[index]}

Nawiasy klamrowe są wymagane dla (większości / wszystkich?) Odniesień do tablicy po prawej stronie.

Komentarz ephemienta przypomniał mi, że nawiasy są również używane do podpowłoki. I że są one używane do tworzenia tablic.

array=(1 2 3)
echo ${array[1]}
2
Wstrzymano do odwołania.
źródło
8
OSTRZEŻENIE: Ta funkcja jest bombą widełkową, nie uruchamiaj jej. Zobacz: en.wikipedia.org/wiki/Fork_bomb
Wstrzymano do odwołania.
3
To tylko bomba widełkowa, jeśli przywołasz ją z dodatkowym :.
ephemient
7
Również dla kompletności, natknąłem się na to w starym skrypcie $[expression]:; to jest stara, przestarzała składnia arytmetyczna wyrażenia dla nowszej, preferowanej składni:$((expression))
michael,
2
@DennisWilliamson Innym zastosowaniem nawiasów klamrowych bashjest tworzenie sekwencji, jak wspomniano poniżej peryferyjnie ( stackoverflow.com/a/8552128/2749397 ) Chciałbym skomentować nieco tę funkcję (o której nie wspomniałeś ;-) m pozwalając sobie na użycie najczęściej głosowanej odpowiedzi jako pojazdu ... Dwa przykłady literałów sekwencji: echo {01..12}-> 01 02 03 04 05 06 07 08 09 10 11 12(zwróć uwagę na początkowe zero); echo {C..Q}-> C D E F G H I J K L M N O P Q. Jego głównym zastosowaniem są pętle, np. for cnt in {01..12} ; do ... ${cnt} ... ; done
gboffi
1
@gboffi: Funkcja dopełniania zera stała się dostępna w Bash 4. Ponadto w Bash 4 możesz określić przyrost w sekwencji: echo {01..12..2}-> „01 03 05 07 09 11”. Dzięki za przypomnienie o sekwencjach. Dodam to do mojej odpowiedzi.
Wstrzymano do odwołania.
335
  1. Pojedynczy nawias kwadratowy ( [) zwykle wywołuje program o nazwie [; man testlub man [po więcej informacji. Przykład:

    $ VARIABLE=abcdef
    $ if [ $VARIABLE == abcdef ] ; then echo yes ; else echo no ; fi
    yes
  2. Podwójny nawias ( [[) robi to samo (w zasadzie) jak pojedynczy nawias, ale jest wbudowany w bash.

    $ VARIABLE=abcdef
    $ if [[ $VARIABLE == 123456 ]] ; then echo yes ; else echo no ; fi
    no
  3. Nawiasy ( ()) służą do tworzenia podpowłoki. Na przykład:

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

    Jak widać, podpowłoka umożliwia wykonywanie operacji bez wpływu na środowisko bieżącej powłoki.

  4. (a) Aparat ortodontyczny ({} ) służą do jednoznacznej identyfikacji zmiennych. Przykład:

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

    (b) Nawiasy klamrowe są również używane do wykonywania sekwencji poleceń w bieżącym kontekście powłoki, np

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

Istnieje jednak subtelna różnica składniowa z ( )(patrz odniesienie do bash ); zasadniczo, średnik ;po ostatnim poleceniu w szelki jest koniecznością, a szelki {, } muszą być otoczone spacjami.

Carl Norum
źródło
26
Cóż, [tak naprawdę jest wbudowany w Bash, ale powinien działać jak /bin/[w przeciwieństwie do [[wbudowanego. [[ma różne funkcje, takie jak bardziej logiczne operacje i różne role cytowania. Dodatkowo: pojedyncze nawiasy są również używane do tablic, podstawiania procesów i rozszerzonych globów; w arytmetyce stosowane są podwójne nawiasy; nawiasy klamrowe {}są używane do grupowania poleceń lub mnóstwa typów interpretacji parametrów, interpretacji nawiasów lub interpretacji sekwencji. Jestem pewien, że przegapiłem też inne zastosowania ...
efhemient
4
Podwójna równość w wyrażeniu if [ $VARIABLE == abcdef ]to bazizm, którego - choć działa - prawdopodobnie należy go unikać; jawnie użyj bash ( if [[ ...==...]]) lub wyjaśnij, że używasz bardziej tradycyjnej metody warunkowej ( if [ "$VARIABLE" = "abcdef" ]). Prawdopodobnie skrypty powinny zaczynać się tak prosto i przenośnie, jak to możliwe, dopóki nie będą naprawdę potrzebować funkcji specyficznych dla bash (z tego czy innego powodu). Ale w każdym razie intencja powinna być jasna; „=” i „==” oraz „[[” i „[” działają inaczej, a ich użycie powinno być spójne.
michael,
3
@michael_n: +1 dla tej uwagi. Na marginesie, uwielbiam skrypty, ale wydaje mi się dość dziwne, że przenośny sposób polega na testowaniu [ "$var" = ".."]zamiast ==, podczas gdy w C przypisuje zamiast testowania (i jest dość częstą przyczyną błędów) ... dlaczego nie „t testużywać ==zamiast =? ktokolwiek wie?
Olivier Dulac
Jest też zabawna rzecz, że (przynajmniej na Kubuntu) polecenie /usr/bin/[nie jest dowiązaniem symbolicznym do /usr/bin/test, a nawet więcej: te programy mają nawet kilka różnych rozmiarów!
Cześć Anioł
Ponadto: pojedynczy nawias zamykający )jest częścią caseskładni instrukcji kończącej wiersz wielkości liter. Nie ma nawiasu otwierającego. To mnie odrzuciło, gdy zobaczyłem to po raz pierwszy.
Agustín Amenabar
302

Wsporniki

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

Nawiasy klamrowe

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

Zdanie wtrącone

( 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 

Podwójne nawiasy

(( 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
źródło
@Yola, czy mógłbyś wyjaśnić, czym dokładnie jest $ (nazwa_warstwy)? W projektach Apple Xcode mogę określić ścieżki plików jako wejście / wyjście skryptu. jeśli podam $ SRC_ROOT / myFile.txt lub $ {SRC_ROOT} /myFile.txt (SRC_ROOT var jest eksportowany przez system kompilacji) - nie działa. działa tylko $ (SRC_ROOT) /myFile.txt. Co może być przyczyną? Wyraźnie var name nie jest poleceniem?
Motti Shneor
1
@MottiShneor, w twoim przypadku $(varname)nie ma związku ze składnią bash. Jest to część składni Makefile .
Sasha
Nie tak - Xcode nie buduje się przy użyciu plików makefile, a jego zmienne są zmiennymi środowiskowymi. Zastrzeżone procesy systemu kompilacji Xcode odczytują wartości tych predefiniowanych zmiennych środowiskowych. Niestandardowe kroki kompilacji to zwykłe skrypty powłoki (bash lub inne) i mają dostęp do tych samych zmiennych.
Motti Shneor
@MottiShneor, ok, dopracujmy: najprawdopodobniej jest to część składni xcconfig . W każdym razie $(varname)nie ma związku ze składnią bash w twoim przypadku.
Sasha
Nie wspominasz o różnicy między konstrukcją testową a rozszerzoną konstrukcją testową.
Nikos
23

Chciałem tylko dodać te z 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
kzh
źródło
18
Umysł echo ${#ARRAY}wyświetla trzy, ponieważ pierwszy element ARRAYzawiera trzy znaki, a nie dlatego, że zawiera trzy elementy! Aby wydrukować liczbę elementów, użyj echo ${#ARRAY[@]}.
TrueY
@zeal ${TEST:-test}jest równe, $TESTjeśli zmienna TESTistnieje, w przeciwnym razie po prostu zwraca ciąg „test”. Jest jeszcze inna wersja, która robi jeszcze więcej: ${TEST:=test}--- która równa się również, $TESTjeśli TEST istnieje, ale ilekroć nie istnieje, tworzy zmienną TESTi przypisuje wartość „test”, a także staje się wartością całego wyrażenia.
Loves Prawdopodobieństwo
18

Różnica między testem , [ i [[ jest szczegółowo wyjaśniona w BashFAQ .

Krótko mówiąc: test implementuje starą, przenośną składnię polecenia. W prawie wszystkich powłokach (najstarsze powłoki Bourne'a są wyjątkiem), [jest synonimem testu (ale wymaga ostatniego argumentu]). Chociaż wszystkie współczesne powłoki mają wbudowane implementacje [, zwykle nadal istnieje zewnętrzny plik wykonywalny o tej nazwie, np. / Bin / [.

[[to nowa ulepszona wersja, która jest słowem kluczowym, a nie programem. Ma to korzystny wpływ na łatwość użycia, jak pokazano poniżej. [[jest rozumiany przez KornShell i BASH (np. 2.03), ale nie przez starsze POSIX lub BourneShell.

I wniosek:

Kiedy należy użyć nowego polecenia testowego [[, a kiedy starego [? Jeśli problemem jest przenośność do BourneShell, należy użyć starej składni. Jeśli z drugiej strony skrypt wymaga BASH lub KornShell, nowa składnia jest znacznie bardziej elastyczna.

bicie
źródło
18

Nawiasy w definicji funkcji

()W definicji funkcji używane są nawiasy :

function_name () { command1 ; command2 ; }

Oto powód, dla którego musisz uciec od nawiasów nawet w parametrach polecenia:

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

$ echo \(
(

$ echo () { command echo The command echo was redefined. ; }
$ echo anything
The command echo was redefined.
pabouk
źródło
Och, próbowałem na csh. Mój błąd. Kiedy próbuję bash, to działa. Nie znałem polecenia „polecenie” bash.
Chan Kim,
jak mogę anulować redefinicję polecenia echo ()? (bez ponownego otwierania uderzenia)
Chan Kim
2
@ChanKim: unset -f echo. Zobaczyć help unset.
pabouk
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
Vuppala Srikar
źródło
Odpowiadając na pytanie, staraj się nie tylko „kodować”, ale także spróbuj dodać wyjaśnienie ...
Mikev