Cara menggunakan kurung ganda atau tunggal, kurung, kurung kurawal


658

Saya bingung dengan penggunaan tanda kurung, kurung, kurung kurawal di Bash, serta perbedaan antara bentuk ganda atau tunggal. Apakah ada penjelasan yang jelas?

Jawaban:


606

Di Bash, testdan [shell builtins.

The bracket ganda , yang merupakan kata kunci shell, memungkinkan fungsionalitas tambahan. Misalnya, Anda dapat menggunakan &&dan ||bukannya -adan -odan ada operator pencocokan ekspresi reguler =~.

Juga, dalam tes sederhana, kurung kotak ganda tampaknya mengevaluasi cukup banyak lebih cepat daripada yang tunggal.

$ 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

Kawat gigi, selain membatasi nama variabel digunakan untuk ekspansi parameter sehingga Anda dapat melakukan hal-hal seperti:

  • Potong isi suatu variabel

    $ var="abcde"; echo ${var%d*}
    abc
    
  • Buat penggantinya mirip dengan sed

    $ var="abcde"; echo ${var/de/12}
    abc12
    
  • Gunakan nilai default

    $ default="hello"; unset var; echo ${var:-$default}
    hello
    
  • dan beberapa lainnya

Juga, ekspansi brace membuat daftar string yang biasanya diulang dalam loop:

$ 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

Perhatikan bahwa fitur zero and increment terdepan tidak tersedia sebelum Bash 4.

Terima kasih kepada gboffi untuk mengingatkan saya tentang ekspansi brace.

Tanda kurung ganda digunakan untuk operasi aritmatika :

((a++))

((meaning = 42))

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

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

dan mereka memungkinkan Anda untuk menghilangkan tanda dolar pada variabel integer dan array dan menyertakan spasi di sekitar operator agar mudah dibaca.

Kurung tunggal juga digunakan untuk indeks array :

array[4]="hello"

element=${array[index]}

Curly brace diperlukan untuk referensi array (sebagian besar / semua?) Di sebelah kanan.

komentar ephemient mengingatkan saya bahwa tanda kurung juga digunakan untuk subkulit. Dan mereka digunakan untuk membuat array.

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

8
PERINGATAN: Fungsi itu adalah bom fork, jangan jalankan. Lihat: en.wikipedia.org/wiki/Fork_bomb
Dijeda hingga pemberitahuan lebih lanjut.

3
Ini hanya bom fork jika Anda memintanya dengan tambahan :.
ephemient

7
Juga untuk kelengkapan, saya hanya datang di dalam sebuah naskah tua: $[expression]; ini adalah sintaks ekspresi aritmatika lama, usang untuk sintaks yang lebih baru, lebih disukai:$((expression))
michael

2
@ DennisWilliamson Penggunaan lain dari kurung kurawal di bashadalah menciptakan urutan, seperti yang disebutkan di bawah ini ( stackoverflow.com/a/8552128/2749397 ) Karena saya ingin sedikit mengomentari fitur ini (karena Anda tidak menyebutkannya ;-) Saya ' m mengambil kebebasan menggunakan jawaban yang paling banyak dipilih sebagai kendaraan ... Dua contoh urutan literal: echo {01..12}-> 01 02 03 04 05 06 07 08 09 10 11 12(perhatikan nol awal); echo {C..Q}-> C D E F G H I J K L M N O P Q. Penggunaan utamanya adalah dalam loop, misalnya, for cnt in {01..12} ; do ... ${cnt} ... ; done
gboffi

1
@ gboffi: Fitur zero padding menjadi tersedia di Bash 4. Selain itu, di Bash 4, Anda dapat menentukan kenaikan secara berurutan: echo {01..12..2}-> "01 03 05 07 09 11". Terima kasih atas pengingat tentang urutan. Saya akan menambahkannya ke jawaban saya.
Dijeda sampai pemberitahuan lebih lanjut.

336
  1. Braket tunggal ( [) biasanya sebenarnya memanggil program bernama [; man testatau man [untuk info lebih lanjut. Contoh:

    $ VARIABLE=abcdef
    $ if [ $VARIABLE == abcdef ] ; then echo yes ; else echo no ; fi
    yes
    
  2. Braket ganda ( [[) melakukan hal yang sama (pada dasarnya) sebagai braket tunggal, tetapi merupakan bash bawaan.

    $ VARIABLE=abcdef
    $ if [[ $VARIABLE == 123456 ]] ; then echo yes ; else echo no ; fi
    no
    
  3. Tanda kurung ( ()) digunakan untuk membuat subkulit. Sebagai contoh:

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

    Seperti yang Anda lihat, subkulit memungkinkan Anda untuk melakukan operasi tanpa mempengaruhi lingkungan shell saat ini.

  4. (a) Kawat gigi ( {}) digunakan untuk mengidentifikasi variabel secara jelas. Contoh:

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

    (B) Kawat gigi juga digunakan untuk mengeksekusi urutan perintah dalam konteks shell saat ini , misalnya

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

Ada perbedaan sintaksis yang halus dengan ( ), (lihat referensi bash ); pada dasarnya, tanda titik koma ;setelah perintah terakhir dalam kawat gigi adalah suatu keharusan, dan kawat gigi {, } harus dikelilingi oleh spasi.


26
Ya, [sebenarnya builtin di Bash, tetapi seharusnya bertindak seperti /bin/[berlawanan dengan [[builtin. [[memiliki fitur yang berbeda, seperti operasi yang lebih logis dan peran kutipan yang berbeda. Selain itu: tanda kurung tunggal juga digunakan untuk array, substitusi proses, dan glob diperpanjang; tanda kurung ganda digunakan untuk aritmatika; kurung kurawal {}digunakan untuk pengelompokan perintah atau banyak jenis ekspansi parameter atau ekspansi kurung atau ekspansi urutan. Saya yakin saya telah melewatkan beberapa kegunaan lain juga ...
ephemient

4
Double-equals dalam ekspresi if [ $VARIABLE == abcdef ]adalah bashism yang - meskipun berfungsi - mungkin harus dihindari; baik menggunakan bash ( if [[ ...==...]]) secara eksplisit atau memperjelas bahwa Anda menggunakan conditional ( if [ "$VARIABLE" = "abcdef" ]) yang lebih tradisional . Dapat diperdebatkan, skrip harus dimulai sesederhana dan semudah mungkin, hingga benar-benar membutuhkan fitur khusus untuk bash (karena satu dan lain hal). Tetapi bagaimanapun juga, tujuannya harus jelas; "=" dan "==" dan "[[" dan "[" berfungsi secara berbeda dan penggunaannya harus konsisten.
michael

3
@michael_n: +1 untuk komentar ini. Di samping catatan, saya suka scripting, tapi saya merasa cukup canggung bahwa cara portabel untuk menguji melalui [ "$var" = ".."]alih-alih ==, sedangkan di C akan menetapkan bukan pengujian (dan merupakan penyebab bug yang cukup umum) ... mengapa tidak bisa testdigunakan ==bukan =? ada yang tahu?
Olivier Dulac

Juga ada hal yang lucu bahwa (setidaknya di Kubuntu) perintahnya /usr/bin/[bukan symlink ke /usr/bin/test, dan banyak lagi: program-program ini bahkan memiliki beberapa ukuran yang berbeda!
Hi-Angel

Juga: tanda kurung tutup tunggal )adalah bagian dari casesintaks pernyataan untuk mengakhiri garis kasus. Itu tidak memiliki tanda kurung buka. Ini melempar saya dari pertama kali saya melihatnya.
AgustĂ­n Amenabar

302

Kurung

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

Kurung kurawal

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

Tanda kurung

( 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 

Tanda kurung ganda

(( 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, bisa tolong jelaskan apa sebenarnya $ (varname)? Dalam proyek-proyek Apple Xcode, saya dapat menentukan jalur file sebagai input / output skrip. jika saya menentukan $ SRC_ROOT / myFile.txt atau $ {SRC_ROOT} /myFile.txt (SRC_ROOT var diekspor oleh sistem build) - tidak berfungsi. hanya $ (SRC_ROOT) /myFile.txt yang berfungsi. Apa yang bisa menjadi alasannya? jelas nama mereka bukan perintah?
Motti Shneor

1
@MottiShneor, dalam kasus Anda $(varname)tidak terkait dengan sintaks bash. Itu adalah bagian dari sintaks Makefile .
Sasha

Tidak demikian - Xcode tidak membangun menggunakan makefile dan variabelnya adalah variabel lingkungan. Proses sistem propiletary Xcode membaca nilai dari variabel-variabel lingkungan yang telah ditentukan ini. Custom-build-step hanyalah skrip shell biasa (bash atau lainnya) dan memiliki akses ke vars yang sama.
Motti Shneor

@MottiShneor, ok, mari kita perbaiki: kemungkinan besar itu adalah bagian dari sintaks xcconfig . Bagaimanapun, $(varname)tidak ada hubungannya dengan sintaks bash dalam kasus Anda.
Sasha

Anda tidak menyebutkan apa perbedaan antara tes konstruksi dan tes konstruksi diperpanjang.
Nikos

23

Saya hanya ingin menambahkan ini dari 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
Pikiran yang echo ${#ARRAY}menampilkan tiga, karena elemen pertama ARRAYberisi tiga karakter, bukan karena mengandung tiga elemen! Untuk mencetak jumlah elemen yang digunakan echo ${#ARRAY[@]}.
TrueY

@zeal ${TEST:-test}sama dengan $TESTjika variabel TESTada, jika tidak, ia hanya mengembalikan string "test". Ada versi lain yang bahkan lebih: ${TEST:=test}--- yang juga sama dengan $TESTjika TEST ada, tetapi setiap kali tidak ada, itu menciptakan variabel TESTdan memberikan nilai "tes" dan juga menjadi nilai dari keseluruhan ekspresi.
Loves Probability

18

Perbedaan antara tes , [ dan [[ dijelaskan dengan sangat rinci di BashFAQ .

Singkat cerita: test mengimplementasikan sintaksis portabel yang lama dari perintah tersebut. Di hampir semua cangkang (cangkang Bourne tertua adalah pengecualian), [adalah sinonim untuk pengujian (tetapi membutuhkan argumen akhir]). Meskipun semua shell modern memiliki implementasi bawaan [, biasanya masih ada executable eksternal dari nama itu, misalnya / bin / [.

[[adalah versi baru yang disempurnakan, yang merupakan kata kunci, bukan program. Ini memiliki efek menguntungkan pada kemudahan penggunaan, seperti yang ditunjukkan di bawah ini. [[dipahami oleh KornShell dan BASH (mis. 2.03), tetapi tidak oleh POSIX atau BourneShell yang lebih lama).

Dan kesimpulannya:

Kapan seharusnya perintah uji yang baru [[digunakan, dan kapan yang lama [? Jika portabilitas ke BourneShell menjadi perhatian, sintaks lama harus digunakan. Jika di sisi lain skrip membutuhkan BASH atau KornShell, sintaks baru jauh lebih fleksibel.


18

Kurung dalam definisi fungsi

Tanda kurung ()sedang digunakan dalam definisi fungsi:

function_name () { command1 ; command2 ; }

Itulah alasan Anda harus keluar dari tanda kurung bahkan dalam parameter perintah:

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

$ echo \(
(

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

Oh saya mencoba di csh. Salahku. Ketika saya mencoba di bash, itu berhasil. Saya tidak tahu perintah 'perintah' dari bash.
Chan Kim

bagaimana saya bisa membatalkan redefinisi command echo ()? (tanpa membuka kembali pesta)
Chan Kim

2
@ChanKim: unset -f echo. Lihat 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

Ketika Anda menjawab pertanyaan, jangan hanya bertujuan untuk "kode", tetapi juga mencoba untuk menambahkan penjelasan ...
Mikev
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.