Saya agak bingung tentang apa yang dilakukan operator ini secara berbeda ketika digunakan dalam bash (kurung, kurung ganda, kurung dan kurung ganda).
[[ , [ , ( , ((
Saya telah melihat orang menggunakannya jika pernyataan seperti ini:
if [[condition]]
if [condition]
if ((condition))
if (condition)
Jawaban:
Sebuah
if
pernyataan biasanya terlihat sepertiThe
then
klausul dijalankan jika kode keluar daricommands1
nol. Jika kode keluar bukan nol, makaelse
klausa dieksekusi.commands1
bisa sederhana atau kompleks. Hal ini dapat, misalnya, menjadi urutan satu atau lebih jaringan pipa dipisahkan oleh salah satu operator;
,&
,&&
, atau||
. Theif
kondisi di bawah ini merupakan kasus hanya khususcommands1
:if [ condition ]
Ini adalah
test
perintah shell tradisional . Ini tersedia di semua shell POSIX. Perintah tes menetapkan kode keluar danif
pernyataan itu bertindak sesuai. Tes umum adalah apakah ada file atau satu nomor sama dengan yang lain.if [[ condition ]]
Ini adalah variasi baru yang ditingkatkan pada
test
dari ksh yang juga mendukung bash dan zsh .test
Perintah ini juga menetapkan kode keluar danif
pernyataan bertindak sesuai. Di antara fitur-fiturnya yang diperluas, dapat menguji apakah string cocok dengan ekspresi reguler.if ((condition))
Lain ksh ekstensi yang menampar dan zsh juga mendukung. Ini melakukan aritmatika. Sebagai hasil dari aritmatika, kode keluar diatur dan
if
pernyataan bertindak sesuai. Ini mengembalikan kode keluar dari nol (benar) jika hasil perhitungan aritmatika adalah nol. Seperti[[...]]
, formulir ini bukan POSIX dan karenanya tidak portabel.if (command)
Ini menjalankan perintah dalam sebuah subkulit. Ketika perintah selesai, itu menetapkan kode keluar dan
if
pernyataan itu bertindak sesuai.Alasan khas untuk menggunakan subkulit seperti ini adalah untuk membatasi efek samping
command
jikacommand
diperlukan tugas variabel atau perubahan lain ke lingkungan shell. Perubahan tersebut tidak tetap setelah subkulit selesai.if command
perintah dieksekusi dan
if
pernyataan itu bertindak sesuai dengan kode keluarnya.sumber
[
sebenarnya biner, bukan perintah atau simbol internal. Umumnya tinggal di/bin
.[
adalah built in, sebagaimana adanyatest
. Ada versi biner yang tersedia untuk alasan kompatibilitas. Lihathelp [
danhelp test
.$((
yaitu ekspansi aritmatika adalah dan mudah untuk membingungkan mereka. Seringkali solusi adalah dengan menggunakan sesuatu seperti[ $((2+2)) -eq 4 ]
menggunakan aritmatika dalam pernyataan conditinal(…)
tanda kurung menunjukkan subkulit . Apa yang ada di dalamnya bukan ekspresi seperti dalam banyak bahasa lain. Ini daftar perintah (seperti tanda kurung di luar). Perintah-perintah ini dieksekusi dalam subproses terpisah, sehingga setiap pengalihan, penugasan, dll yang dilakukan di dalam tanda kurung tidak memiliki efek di luar tanda kurung.$(…)
adalah substitusi perintah : ada perintah di dalam tanda kurung, dan output dari perintah digunakan sebagai bagian dari baris perintah (setelah ekspansi tambahan kecuali substitusi berada di antara tanda kutip ganda, tapi itu cerita lain ) .{ … }
kurung kurawal seperti tanda kurung di mana mereka mengelompokkan perintah, tetapi mereka hanya mempengaruhi penguraian, bukan pengelompokan. Programx=2; { x=4; }; echo $x
mencetak 4, sedangkanx=2; (x=4); echo $x
cetakan 2. (Juga tanda kurung menjadi kata kunci perlu dibatasi dan ditemukan dalam posisi perintah (maka spasi setelah{
dan;
sebelumnya}
) sedangkan tanda kurung tidak. Itu hanya sebuah sintaks sintaksis.)${VAR}
adalah ekspansi parameter , yang diperluas ke nilai variabel, dengan kemungkinan transformasi tambahan. Theksh93
shell juga mendukung${ cmd;}
sebagai bentuk perintah substitusi yang tidak menelurkan subkulit.((…))
tanda kurung ganda mengelilingi instruksi aritmatika , yaitu, perhitungan pada bilangan bulat, dengan sintaksis yang menyerupai bahasa pemrograman lain. Sintaks ini sebagian besar digunakan untuk penugasan dan dalam kondisi. Ini hanya ada di ksh / bash / zsh, bukan di sh polos.$((…))
, yang diperluas ke nilai integer ekspresi.[ … ]
kurung tunggal mengelilingi ekspresi bersyarat . Ekspresi bersyarat sebagian besar dibangun pada operator seperti-n "$variable"
untuk menguji apakah suatu variabel kosong dan-e "$file"
untuk menguji apakah ada file. Perhatikan bahwa Anda memerlukan ruang di sekitar setiap operator (mis[ "$x" = "$y" ]
. Tidak), dan spasi atau karakter seperti[ "$x"="$y" ]
;
di dalam dan di luar tanda kurung (misalnya[ -n "$foo" ]
, tidak).[-n "$foo"]
[[ … ]]
kurung ganda adalah bentuk alternatif dari ekspresi kondisional dalam ksh / bash / zsh dengan beberapa fitur tambahan, misalnya Anda dapat menulis[[ -L $file && -f $file ]]
untuk menguji apakah suatu file merupakan tautan simbolis ke file biasa sedangkan kurung tunggal memerlukan[ -L "$file" ] && [ -f "$file" ]
. Lihat Mengapa ekspansi parameter dengan spasi tanpa tanda kutip bekerja di dalam tanda kurung ganda [[tetapi bukan tanda kurung tunggal [? untuk lebih lanjut tentang topik ini.Dalam shell, setiap perintah adalah perintah kondisional: setiap perintah memiliki status pengembalian yang 0 menunjukkan keberhasilan atau bilangan bulat antara 1 dan 255 (dan berpotensi lebih banyak di beberapa shell) menunjukkan kegagalan. The
[ … ]
perintah (atau[[ … ]]
bentuk sintaks) adalah perintah tertentu yang juga bisa dibilangtest …
dan berhasil bila file ada, atau ketika string tidak kosong, atau ketika angka lebih kecil dari yang lain, dll((…))
bentuk sintaks berhasil ketika sejumlah bukan nol. Berikut adalah beberapa contoh kondisional dalam skrip shell:Tes jika
myfile
berisi stringhello
:Jika
mydir
direktori, ubah dan lakukan hal-hal:Uji apakah ada file yang dipanggil
myfile
di direktori saat ini:Hal yang sama, tetapi juga termasuk tautan simbolik yang menjuntai:
Tes jika nilai
x
(yang dianggap numerik) setidaknya 2, dengan mudah:Tes jika nilai
x
(yang dianggap numerik) setidaknya 2, dalam bash / ksh / zsh:sumber
-a
alih - alih&&
, sehingga orang dapat menulis:,[ -L $file -a -f $file ]
yang merupakan jumlah karakter yang sama dalam tanda kurung tanpa tambahan[
dan]
...-a
dan-o
bermasalah karena mereka dapat menyebabkan parse yang salah jika beberapa operan yang terlibat terlihat seperti operator. Itu sebabnya saya tidak menyebut mereka: mereka tidak memiliki keunggulan dan tidak selalu berhasil. Dan jangan pernah menulis ekspansi variabel tanpa tanda kutip tanpa alasan yang baik:[[ -L $file -a -f $file ]]
baik-baik saja tetapi dengan tanda kurung tunggal yang Anda butuhkan[ -L "$file" -a -f "$file" ]
(yang ok misalnya jika$file
selalu dimulai dengan/
atau./
).[[ -L $file && -f $file ]]
(tidak-a
dengan[[...]]
varian).Dari dokumentasi bash :
Dengan kata lain, Anda memastikan bahwa apa pun yang terjadi di 'daftar' (seperti a
cd
) tidak berpengaruh di luar(
dan)
. Satu-satunya hal yang akan bocor adalah kode keluar dari perintah terakhir atau denganset -e
perintah pertama yang menghasilkan kesalahan (selain beberapa sepertiif
,while
, dll)Ini adalah ekstensi bash yang memungkinkan Anda melakukan matematika. Ini agak mirip dengan menggunakan
expr
tanpa semua keterbatasanexpr
(seperti memiliki ruang di mana-mana, melarikan diri*
, dll.)Ini menawarkan tes lanjutan untuk membandingkan string, angka, dan file sedikit seperti
test
penawaran, tetapi lebih kuat.Yang ini panggilan
test
. Sebenarnya, di masa lalu,[
adalah tautan simbolis ketest
. Ini bekerja dengan cara yang sama dan Anda memiliki keterbatasan yang sama. Karena biner mengetahui nama yang digunakannya untuk memulai, program uji dapat mengurai parameter sampai ia menemukan parameter]
. Trik Unix yang menyenangkan.Perhatikan bahwa dalam kasus
bash
,[
dantest
merupakan fungsi bawaan (seperti yang disebutkan dalam komentar), namun batasan yang hampir sama berlaku.sumber
test
dan[
tentu saja dibangun dalam perintah di Bash, tetapi kemungkinan biner eksternal juga ada.[
bukan merupakan tautan simbolis ketest
pada kebanyakan sistem modern.strings /usr/bin/test
menunjukkan itu memiliki teks bantuan juga, jadi saya tidak tahu harus berkata apa.test
perintah jelas diperlukan untuk ada sebagai perintah berbasis file mandiri oleh standar, tidak ada di dalamnya menyatakan[
variannya perlu diimplementasikan dengan cara itu juga. Sebagai contoh, Solaris 11 tidak menyediakan yang[
dapat dieksekusi tetapi tetap sepenuhnya sesuai dengan standar POSIX[
vs.[[
Jawaban ini akan mencakup
[
vs[[
subset dari pertanyaan.Beberapa perbedaan pada Bash 4.3.11:
Ekstensi POSIX vs Bash:
[
adalah POSIX[[
adalah ekstensi Bash¹ didokumentasikan di: https://www.gnu.org/software/bash/manual/bash.html#Conditional-Constructsperintah reguler vs sihir
[
hanyalah perintah biasa dengan nama yang aneh.]
hanyalah argumen[
yang mencegah argumen lebih lanjut digunakan.Ubuntu 16.04 sebenarnya memiliki executable yang
/usr/bin/[
disediakan oleh coreutils, tetapi versi built-in bash lebih diutamakan.Tidak ada yang diubah dalam cara Bash mem-parsing perintah.
Secara khusus,
<
pengalihan,&&
dan||
menggabungkan beberapa perintah,( )
menghasilkan subkulit kecuali lolos\
, dan perluasan kata terjadi seperti biasa.[[ X ]]
adalah konstruksi tunggal yang membuatX
diurai secara ajaib.<
,&&
,||
Dan()
diperlakukan khusus, dan aturan kata membelah berbeda.Ada juga perbedaan lebih lanjut seperti
=
dan=~
.Dalam Bashese:
[
adalah perintah bawaan , dan[[
merupakan kata kunci: https://askubuntu.com/questions/445749/whats-the-difference-between-shell-builtin-and-shell-keyword<
[[ a < b ]]
: perbandingan leksikografis[ a \< b ]
: Sama seperti di atas.\
diperlukan atau jika tidak pengalihan seperti untuk perintah lain. Ekstensi bash.expr a \< b > /dev/null
: POSIX equivalent², lihat: https://stackoverflow.com/questions/21294867/how-to-test-strings-for-lexicographic-less-than-or-equal-in-bash/52707989#52707989&&
dan||
[[ a = a && b = b ]]
: benar, logis dan[ a = a && b = b ]
: kesalahan sintaks,&&
diurai sebagai pemisah perintah ANDcmd1 && cmd2
[ a = a -a b = b ]
: setara, tetapi ditinggalkan oleh POSIX by[ a = a ] && [ b = b ]
: POSIX dan setara yang dapat diandalkan(
[[ (a = a || a = b) && a = b ]]
: Salah[ ( a = a ) ]
: kesalahan sintaksis,()
ditafsirkan sebagai subkulit[ \( a = a -o a = b \) -a a = b ]
: ekuivalen, tetapi()
ditinggalkan oleh POSIX{ [ a = a ] || [ a = b ]; } && [ a = b ]
Setara dengan POSIX 5pemisahan kata dan pembuatan nama file berdasarkan ekspansi (split + glob)
x='a b'; [[ $x = 'a b' ]]
: true, kutipan tidak diperlukanx='a b'; [ $x = 'a b' ]
: kesalahan sintaks, diperluas ke[ a b = 'a b' ]
x='*'; [ $x = 'a b' ]
: kesalahan sintaks jika ada lebih dari satu file di direktori saat ini.x='a b'; [ "$x" = 'a b' ]
: Setara POSIX=
[[ ab = a? ]]
: benar, karena tidak cocok dengan pola (* ? [
adalah sihir). Tidak glob berkembang ke file dalam direktori saat ini.[ ab = a? ]
:a?
glob berkembang. Jadi mungkin benar atau salah tergantung pada file di direktori saat ini.[ ab = a\? ]
: false, bukan ekspansi glob=
dan==
sama di keduanya[
dan[[
, tetapi==
merupakan ekstensi Bash.case ab in (a?) echo match; esac
: Setara POSIX[[ ab =~ 'ab?' ]]
: false 4 , kehilangan sihir dengan''
[[ ab? =~ 'ab?' ]]
: benar=~
[[ ab =~ ab? ]]
: true, POSIX memperpanjang kecocokan ekspresi reguler ,?
tidak glob berkembang[ a =~ a ]
: kesalahan sintaks. Tidak setara dengan bash.printf 'ab\n' | grep -Eq 'ab?'
: Setara POSIX (hanya data garis tunggal)awk 'BEGIN{exit !(ARGV[1] ~ ARGV[2])}' ab 'ab?'
: Setara POSIX.Rekomendasi : selalu gunakan
[]
.Ada setara POSIX untuk setiap
[[ ]]
konstruk yang pernah saya lihat.Jika Anda menggunakan
[[ ]]
Anda:[
hanyalah perintah biasa dengan nama yang aneh, tidak ada semantik khusus yang terlibat.¹ Terinspirasi dari
[[...]]
konstruksi yang setara di shell Korn² tetapi gagal untuk beberapa nilai
a
ataub
(suka+
atauindex
) dan melakukan perbandingan numerik jikaa
danb
terlihat seperti bilangan bulat desimal.expr "x$a" '<' "x$b"
bekerja di sekitar keduanya.³ dan juga gagal untuk beberapa nilai
a
ataub
suka!
atau(
.4 di bash 3.2 dan di atas dan kompatibilitas yang disediakan untuk bash 3.1 tidak diaktifkan (seperti dengan
BASH_COMPAT=3.1
)5 meskipun pengelompokan (di sini dengan
{...;}
kelompok perintah alih-alih(...)
yang akan menjalankan subkulit yang tidak perlu) tidak diperlukan karena operator||
dan&&
shell (sebagai lawan dari||
dan&&
[[...]]
operator atau-o
/-a
[
operator) memiliki prioritas yang sama. Jadi[ a = a ] || [ a = b ] && [ a = b ]
akan setara.sumber
expr
jawabannya. Istilah "ekstensi Bash" tidak dimaksudkan untuk menyiratkan Bash adalah shell pertama yang menambahkan beberapa sintaks, belajar POSIX sh vs Bash sudah cukup untuk membuatku gila.man test
apakah Anda mencobaman [
dan tersesat. Itu akan menjelaskan varian POSIX.Beberapa contoh:
Tes tradisional:
test
dan[
perintah seperti yang lain, sehingga variabel ini dibagi menjadi kata-kata kecuali dalam tanda kutip.Tes gaya baru
[[ ... ]]
adalah konstruksi shell khusus (yang lebih baru), yang bekerja sedikit berbeda, hal yang paling jelas adalah bahwa ia tidak menggunakan variabel pemisah kata:Beberapa dokumentasi tentang
[
dan di[[
sini .Tes aritmatika:
Perintah "normal":
Semua tindakan di atas seperti perintah normal, dan
if
dapat mengambil perintah apa pun:Banyak perintah:
Atau kita bisa menggunakan banyak perintah. Membungkus seperangkat perintah dalam
( ... )
menjalankannya dalam subkulit, membuat salinan sementara dari status shell (direktori kerja, variabel). Jika kita perlu menjalankan beberapa program sementara di direktori lain:sumber
Perintah Pengelompokan
( list )
Menempatkan daftar perintah di antara tanda kurung menyebabkan lingkungan subkulit dibuat, dan masing-masing perintah dalam daftar dieksekusi di subkulit itu. Karena daftar dieksekusi dalam subkulit, tugas variabel tidak tetap berlaku setelah subkulit selesai.{ list; }
Menempatkan daftar perintah antara kurung kurawal menyebabkan daftar dieksekusi dalam konteks shell saat ini . Tidak ada subkulit yang dibuat. Tanda titik koma (atau baris baru) diperlukan. SumberKonstruksi Bersyarat
Braket Tunggal yaitu
[]
Untuk perbandingan
==, !=, <,
dan>
dan harus digunakan dan untuk perbandingan numerikeq, ne,lt
dangt
harus digunakan.Yaitu Kurung yang Ditingkatkan
[[]]
Dalam semua contoh di atas, kami hanya menggunakan tanda kurung tunggal untuk melampirkan ekspresi bersyarat, tetapi bash memungkinkan tanda kurung ganda yang berfungsi sebagai versi yang disempurnakan dari sintaks braket tunggal.
Untuk perbandingan
==, !=, <,
dan>
dapat digunakan secara harfiah.[
adalah sinonim untuk perintah tes. Bahkan jika itu dibangun ke shell itu menciptakan proses baru.[[
adalah versi baru yang disempurnakan, yang merupakan kata kunci, bukan program.[[
dipahami olehKorn
danBash
.Sumber
sumber