Arti kesalahan “[: terlalu banyak argumen” dari if [] (kurung siku)

212

Saya tidak dapat menemukan satu sumber daya sederhana yang menjelaskan arti dan memperbaiki kesalahan BASH shell berikut, jadi saya memposting apa yang saya temukan setelah meneliti itu.

Kesalahan:

-bash: [: too many arguments

Versi Google ramah-: bash open square bracket colon too many arguments .

Konteks: kondisi if dalam kurung kotak tunggal dengan operator perbandingan sederhana seperti sama, lebih besar dari dll, misalnya:

VARIABLE=$(/some/command);
if [ $VARIABLE == 0 ]; then
  # some action
fi 
user56reinstatemonica8
sumber
1
Di mana kode yang menghasilkan kesalahan khusus ini?
Anderson Green

Jawaban:

354

Jika $VARIABLEstring Anda berisi spasi atau karakter khusus lainnya, dan tanda kurung siku digunakan (yang merupakan pintasan untuk testperintah), maka string tersebut dapat dibagi menjadi beberapa kata. Masing-masing diperlakukan sebagai argumen terpisah.

Sehingga satu variabel dibagi menjadi banyak argumen :

VARIABLE=$(/some/command);  
# returns "hello world"

if [ $VARIABLE == 0 ]; then
  # fails as if you wrote:
  # if [ hello world == 0 ]
fi 

Hal yang sama akan berlaku untuk panggilan fungsi apa pun yang meletakkan string yang berisi spasi atau karakter khusus lainnya.


Memperbaiki mudah

Bungkus output variabel dalam tanda kutip ganda, memaksanya untuk tetap sebagai satu string (karena itu satu argumen). Sebagai contoh,

VARIABLE=$(/some/command);
if [ "$VARIABLE" == 0 ]; then
  # some action
fi 

Sederhana seperti itu. Tetapi lompat ke "Waspadalah juga ..." di bawah ini jika Anda juga tidak dapat menjamin variabel Anda tidak akan menjadi string kosong, atau string yang hanya berisi spasi kosong.


Atau, perbaikan alternatif adalah dengan menggunakan tanda kurung kotak ganda (yang merupakan jalan pintas untuk new testperintah).

Ini hanya ada di bash (dan tampaknya korn dan zsh), dan karenanya mungkin tidak kompatibel dengan shell default yang dipanggil oleh /bin/shdll.

Ini berarti pada beberapa sistem, mungkin bekerja dari konsol tetapi tidak ketika dipanggil di tempat lain, seperti daricron , tergantung pada bagaimana semuanya dikonfigurasi.

Akan terlihat seperti ini:

VARIABLE=$(/some/command);
if [[ $VARIABLE == 0 ]]; then
  # some action
fi 

Jika perintah Anda berisi tanda kurung ganda seperti ini dan Anda mendapatkan kesalahan dalam log tetapi berfungsi dari konsol, coba menukar [[alternatif yang disarankan di sini, atau, pastikan bahwa apa pun yang menjalankan skrip Anda menggunakan shell yang mendukung [[alias new test.


Waspadalah terhadap [: unary operator expectedkesalahan tersebut

Jika Anda melihat kesalahan "terlalu banyak argumen", kemungkinan Anda mendapatkan string dari fungsi dengan output yang tidak dapat diprediksi. Jika juga dimungkinkan untuk mendapatkan string kosong (atau semua string spasi putih), ini akan diperlakukan sebagai argumen nol bahkan dengan "perbaikan cepat" di atas, dan akan gagal dengan[: unary operator expected

Ini sama dengan 'gotcha' jika Anda terbiasa dengan bahasa lain - Anda tidak berharap isi dari variabel dicetak secara efektif ke dalam kode seperti ini sebelum dievaluasi.

Berikut adalah contoh yang mencegah kesalahan [: too many argumentsdan [: unary operator expectedkesalahan: mengganti output dengan nilai default jika kosong (dalam contoh ini, 0), dengan tanda kutip ganda melilit semuanya:

VARIABLE=$(/some/command);
if [ "${VARIABLE:-0}" == 0 ]; then
  # some action
fi 

(di sini, tindakan akan terjadi jika $ VARIABEL adalah 0, atau kosong. Secara alami, Anda harus mengubah 0 (nilai default) ke nilai default yang berbeda jika perilaku yang berbeda diinginkan)


Catatan akhir: Karena [merupakan jalan pintas untuk test, semua hal di atas juga berlaku untuk kesalahan test: too many arguments(dan juga test: unary operator expected)

user56reinstatemonica8
sumber
Cara yang lebih baik adalahi=$(some_command); i=$((i)); if [ "$i" == 0 ] ...
Jo So
1
Saya mengalami masalah ketika Shellscript menggunakan BASH sebagai penerjemah, ketika dieksekusi melalui terminal, akan baik-baik saja, tetapi ketika dieksekusi melalui Crontab, mengalami kegagalan seperti ini dan mengirim email lokal melalui Postfix, menginformasikan kesalahan ini dan saya tahu, bahwa ada a IF untuk variabel yang memiliki karakter khusus. Kutipan ganda menyelamatkan hidupku. Terima kasih :)!
ivanleoncz
13

Hanya menabrak posting ini, dengan mendapatkan kesalahan yang sama, mencoba menguji apakah dua variabel keduanya kosong (atau tidak kosong). Itu ternyata menjadi perbandingan majemuk - 7.3. Operator Perbandingan Lainnya - Panduan Script Bash Lanjutan ; dan saya pikir saya harus perhatikan hal berikut:

  • Saya dulu -eberpikir itu berarti "kosong" pada awalnya; tetapi itu berarti "file ada" - digunakan -zuntuk menguji variabel kosong (string)
  • Variabel string perlu dikutip
  • Untuk perbandingan logika DAN, baik:
    • gunakan dua tests dan &&mereka:[ ... ] && [ ... ]
    • atau gunakan -aoperator dalam satu test:[ ... -a ... ]

Berikut ini adalah perintah yang berfungsi (mencari melalui semua file txt di direktori, dan membuang yang grepmenemukan mengandung dua kata):

find /usr/share/doc -name '*.txt' | while read file; do \
  a1=$(grep -H "description" $file); \
  a2=$(grep -H "changes" $file); \
  [ ! -z "$a1" -a ! -z "$a2"  ] && echo -e "$a1 \n $a2" ; \
done

Sunting 12 Agustus 2013: catatan masalah terkait:

Perhatikan bahwa ketika memeriksa kesetaraan string dengan klasik test(braket persegi tunggal [), Anda HARUS memiliki ruang antara operator "sama", yang dalam hal ini adalah tanda "sama dengan" =(meskipun tanda dua sama ==nampaknya diterima sebagai kesetaraan operator juga). Dengan demikian, ini gagal (diam-diam):

$ if [ "1"=="" ] ; then echo A; else echo B; fi 
A
$ if [ "1"="" ] ; then echo A; else echo B; fi 
A
$ if [ "1"="" ] && [ "1"="1" ] ; then echo A; else echo B; fi 
A
$ if [ "1"=="" ] && [ "1"=="1" ] ; then echo A; else echo B; fi 
A

... tapi tambahkan spasi - dan semua terlihat bagus:

$ if [ "1" = "" ] ; then echo A; else echo B; fi 
B
$ if [ "1" == "" ] ; then echo A; else echo B; fi 
B
$ if [ "1" = "" -a "1" = "1" ] ; then echo A; else echo B; fi 
B
$ if [ "1" == "" -a "1" == "1" ] ; then echo A; else echo B; fi 
B
sdaau
sumber
Bisakah Anda memberikan contoh bash shell ((A || B) && C)?
jww
silakan lihat pertanyaan 3826425 dan 14964805
splaisan
Ini benar-benar tidak berguna dari jawaban karena tidak menunjukkan kepada Anda bagaimana mengandung perintah sepenuhnya dalam kurung siku, yang diperlukan jika ada loop, misalnya.
Timothy Swan
5

Skenario lain yang bisa Anda dapatkan [: too many argumentsatau [: a: binary operator expectedgalat adalah jika Anda mencoba menguji semua argumen"$@"

if [ -z "$@" ]
then
    echo "Argument required."
fi

Ini berfungsi dengan benar jika Anda menelepon foo.shatau foo.sh arg1. Tetapi jika Anda melewati beberapa argumen seperti foo.sh arg1 arg2, Anda akan mendapatkan kesalahan. Ini karena sedang diperluas ke [ -z arg1 arg2 ], yang bukan sintaks yang valid.

Cara yang benar untuk memeriksa adanya argumen adalah [ "$#" -eq 0 ]. ( $#adalah jumlah argumen).

wisbucky
sumber
2

Beberapa kali Jika Anda menyentuh keyboard secara tidak sengaja dan menghapus spasi.

if [ "$myvar" = "something"]; then
    do something
fi

Akan memicu pesan kesalahan ini. Perhatikan spasi sebelum ']' diperlukan.

Kemin Zhou
sumber
1
Saya pikir itu menghasilkan kesalahan sintaks yang berbeda, seperti: baris 21: [: hilang `] '
Joe Holloway
1

Saya memiliki masalah yang sama dengan skrip saya. Tetapi ketika saya melakukan beberapa modifikasi itu berhasil untuk saya. Saya memang suka ini: -

export k=$(date "+%k");
if [ $k -ge 16 ] 
    then exit 0; 
else 
    echo "good job for nothing"; 
fi;

dengan begitu saya menyelesaikan masalah saya. Semoga itu akan membantu Anda juga.

Kidane
sumber