Seorang rekan kerja mengklaim baru-baru ini dalam ulasan kode bahwa [[ ]]
konstruk lebih disukai daripada [ ]
konstruk suka
if [ "`id -nu`" = "$someuser" ] ; then
echo "I love you madly, $someuser"
fi
Dia tidak bisa memberikan alasan. Apakah ada satu?
bash
if-statement
syntax
Leonard
sumber
sumber
[[
kode itu bagus dan jelas, tetapi ingatlah hari itu ketika Anda akan mem-porting skrip Anda pada sistem dengan shell default yang bukanbash
atauksh
, dll[
lebih jelek, rumit, tetapi berfungsi sepertiAK-47
dalam situasi apa pun.Jawaban:
[[
memiliki lebih sedikit kejutan dan umumnya lebih aman untuk digunakan. Tapi itu tidak portabel - POSIX tidak menentukan apa yang dilakukannya dan hanya beberapa shell yang mendukungnya (selain bash, saya mendengar ksh juga mendukungnya). Misalnya, Anda bisa melakukannyauntuk menguji apakah ada file. Tetapi dengan
[
, Anda harus mengutip$b
, karena itu memecah argumen dan memperluas hal-hal seperti"a*"
(di mana[[
menerimanya secara harfiah). Itu juga ada hubungannya dengan bagaimana[
bisa menjadi program eksternal dan menerima argumennya seperti biasanya seperti setiap program lainnya (meskipun itu juga bisa menjadi builtin, tetapi kemudian masih belum penanganan khusus ini).[[
juga memiliki beberapa fitur bagus lainnya, seperti pencocokan ekspresi reguler=~
dan operator seperti mereka dikenal dalam bahasa C-like. Berikut ini adalah halaman yang bagus tentang hal itu: Apa perbedaan antara tes,[
dan[[
? dan Tes Bashsumber
[[ ]]
tetapi mengartikannya sebagai sama artinya[ ]
.#!/bin/sh
tetapi kemudian beralih untuk digunakan#!/bin/bash
segera setelah saya mengandalkan beberapa fitur BASH spesifik, untuk menunjukkan itu bukan lagi Bourne shell portable.Perbedaan perilaku
Beberapa perbedaan pada Bash 4.3.11:
Ekstensi POSIX vs Bash:
[
adalah POSIX[[
adalah ekstensi Bash ¹perintah 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,
<
adalah 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=~
.Di Bashese:
[
adalah perintah bawaan , dan[[
merupakan kata kunci: /ubuntu/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: Bagaimana menguji string untuk lexicographic kurang dari atau sama di Bash?&&
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³[ a = a ] && [ b = b ]
: POSIX dan setara yang dapat diandalkan(
[[ (a = a || a = b) && a = b ]]
: Salah[ ( a = a ) ]
: kesalahan sintaks,()
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⁵pemisahan 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⁴, kehilangan sihir dengan''
[[ ab? =~ 'ab?' ]]
: benar=~
[[ ab =~ ab? ]]
: true, POSIX memperpanjang kecocokan ekspresi reguler ,?
tidak glob berkembang[ a =~ a ]
: kesalahan sintaks. Tidak ada yang 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(
.⁴ di bash 3.2 dan di atas dan kompatibilitas yang disediakan untuk bash 3.1 tidak diaktifkan (seperti dengan
BASH_COMPAT=3.1
)⁵ meskipun pengelompokan (di sini dengan
{...;}
grup 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
[
untuk alasan yang sama.[[ ]]
memiliki lebih banyak fitur - saya sarankan Anda melihat pada Panduan Bash Scripting Lanjutan untuk info lebih lanjut, khususnya bagian perintah uji diperpanjang di Bab 7. Pengujian .Kebetulan, seperti catatan panduan,
[[ ]]
diperkenalkan di ksh88 (versi 1988 dari shell Korn).sumber
Dari pembanding, tes, braket, atau braket ganda mana yang tercepat? ( http://bashcurescancer.com )
sumber
[[
mungkin membawa. Tapi kemudian, aku kentut sekolah tua :-)[
dantest
meskipun versi eksternal juga ada.PS1=...crazy stuff...
dan / atau$PROMPT_COMMAND
); untuk ini, saya tidak ingin ada keterlambatan yang jelas dalam pelaksanaan skrip.apt-get update
jika sudah lebih dari X jam sejak terakhir kali dijalankan. Ini sangat melegakan ketika seseorang dapat meninggalkan portabilitas dari daftar kendala yang sudah terlalu lama untuk kode.Jika Anda mengikuti panduan gaya Google :
Tes,
[
dan[[
sumber
[[ -d ~ ]]
mengembalikan true (yang menyiratkan~
diperluas ke/home/user
). Saya pikir Google seharusnya lebih tepat dalam menulisnya.Situasi khas di mana Anda tidak dapat menggunakan
[[
dalam skrip configure.ac autotools, ada tanda kurung memiliki arti khusus dan berbeda, sehingga Anda harus menggunakantest
bukan[
atau[[
- Perhatikan tes itu dan[
merupakan program yang sama.sumber
[
akan didefinisikan sebagai fungsi shell POSIX?[[]] kurung ganda tidak didukung di bawah versi SunOS tertentu dan deklarasi fungsi dalam yang sepenuhnya tidak didukung oleh: GNU bash, versi 2.02.0 (1) -release (sparc-sun-solaris2.6)
sumber
Singkatnya, [[lebih baik karena tidak perlu proses lain. Tidak ada tanda kurung atau braket tunggal yang lebih lambat dari braket ganda karena braket proses lain.
sumber
type [
untuk melihat ini.[[
, berbeda dari[
, sintaksinya ditafsirkan oleh penerjemah baris perintah bash. Di bash, coba ketikkantype [[
. unix4linux benar bahwa meskipun[
tes Bourne-shell klasik memotong proses baru untuk menentukan nilai kebenaran,[[
sintaks (dipinjam dari ksh oleh bash, zsh, dll) tidak.[
built-in untuk Bash serta Dash (/bin/sh
dalam semua distribusi Linux yang diturunkan dari Debian).