İf [] (köşeli parantez) içindeki “[: çok fazla argüman” hatasının anlamı


212

Aşağıdaki BASH kabuk hatasının anlamını düzeltmek ve düzeltmek için basit bir basit kaynak bulamadım, bu yüzden araştırdıktan sonra bulduğum şeyi gönderiyorum.

Hata:

-bash: [: too many arguments

Google'a uygun versiyon: bash open square bracket colon too many arguments .

Bağlam: eşittir, vb. Gibi daha büyük bir karşılaştırma operatörüne sahip tek köşeli parantezlerde bir if koşulu, örneğin:

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

1
Bu özel hatayı üreten kod nerede?
Anderson Green

Yanıtlar:


354

Sizin $VARIABLEboşluk veya başka özel karakterler içeren bir dize ise ve tek köşeli parantez kullanılıyorsa (bu testkomut için bir kısayoldur ), dize birden çok kelimeye bölünebilir. Bunların her biri ayrı bir argüman olarak ele alınır.

Böylece bir değişken birçok argümana bölünür :

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

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

Aynı şey, boşluk veya diğer özel karakterleri içeren bir dizeyi kapatan herhangi bir işlev çağrısı için de geçerlidir.


Kolay düzeltme

Değişken çıktıyı çift tırnak içine alın ve bir dize (bu nedenle bir bağımsız değişken) olarak kalmaya zorlayın. Örneğin,

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

Bu kadar basit. Ancak, değişkeninizin boş bir dize veya boşluktan başka bir şey içermeyeceğini garanti edemezseniz aşağıdaki "Ayrıca dikkatli olun ..." a atlayın.


Veya alternatif bir düzeltme , çift köşeli parantez kullanmaktır (bu new testkomut için bir kısayoldur ).

Bu sadece bash (ve görünüşte korn ve zsh) olarak bulunur ve bu nedenle /bin/shvb. Olarak adlandırılan varsayılan kabuklarla uyumlu olmayabilir .

Bu, bazı sistemlerde konsoldan çalışabileceğicron anlamına gelir, ancak her şeyin nasıl yapılandırıldığına bağlı olarak başka bir yerde çağrıldığında çalışmayabilir .

Şöyle görünecektir:

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

Komutunuz bunun gibi çift köşeli parantez içeriyorsa ve günlüklerde hata alıyorsanız, ancak konsoldan çalışıyorsa, [[burada önerilen bir alternatifi değiştirmeyi deneyin veya betiğinizi çalıştıran her şeyin [[aka destekleyen bir kabuk kullandığından emin olun new test.


Ayrıca [: unary operator expectedhataya dikkat edin

"Çok fazla argüman" hatası görüyorsanız, öngörülemeyen çıktıya sahip bir işlevden bir dize alıyorsunuzdur. Boş bir dize (veya tüm boşluk dizesi) almak da mümkünse , bu yukarıdaki "hızlı düzeltme" ile bile sıfır bağımsız değişken olarak ele alınır ve başarısız olur[: unary operator expected

Diğer dillere alışkınsanız aynı 'gotcha' - bir değişkenin içeriğinin, değerlendirilmeden önce böyle bir koda etkili bir şekilde basılmasını beklemezsiniz.

İşte bir örnek olduğunu önler hem [: too many argumentsve [: unary operator expectedhatalar: Bu boşsa (bu örnekte varsayılan bir değerle çıktı yerine 0her şeyi sarılı çift tırnak ile,):

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

(burada, $ VARIABLE 0 veya boşsa eylem gerçekleşir. Doğal olarak, farklı davranışlar isteniyorsa 0'ı (varsayılan değer) farklı bir varsayılan değere değiştirmelisiniz)


Son Not: beri [için bir kısayol testtüm yukarıda da hata için de geçerlidir test: too many arguments(aynı zamanda ve test: unary operator expected)


Daha da iyi bir yoli=$(some_command); i=$((i)); if [ "$i" == 0 ] ...
Jo So

1
Tercüman olarak BASH kullanan bir Shellscript'in terminal aracılığıyla yürütüldüğünde sorun çıktığı bir sorun yaşadım, ancak Crontab üzerinden yürütüldüğünde, bu tür hatalar yaşıyor ve Postfix aracılığıyla yerel e-posta gönderiyordu, bu hatayı bildirerek anladım ve özel karakterleri olan bir değişken için EĞER. Çift tırnak hayatımı kurtardı. Teşekkür ederim :)!
ivanleoncz

13

Sadece aynı hatayı alarak, iki değişkenin hem boş ( hem de boş) olup olmadığını test etmeye çalışarak bu gönderiye çarptı . Bileşik bir karşılaştırma olduğu ortaya çıkıyor - 7.3. Diğer Karşılaştırma Operatörleri - Gelişmiş Bash-Scripting Kılavuzu ; ve aşağıdakilere dikkat etmem gerektiğini düşündüm:

  • Kullandığım -eilk başlarda "boş" anlamına düşünme; ancak bu "dosya var" anlamına gelir - -zboş değişkeni (string) test etmek için kullanın
  • Dize değişkenlerinin alıntılanması gerekir
  • Bileşik mantıksal AND karşılaştırması için:
    • iki tests ve &&onları kullanın :[ ... ] && [ ... ]
    • veya -atek bir işleç kullanın test:[ ... -a ... ]

İşte çalışan bir komut (bir dizindeki tüm txt dosyalarında arama ve grepiki kelimeyi içeren buluntuların dökümü):

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

Edit 12 Ağu 2013: ilgili sorun notu:

Klasik test(tek köşeli ayraç [) ile dize eşitliğini kontrol ederken , "eşittir" operatörü arasında bir boşluk olması GEREKİR , bu durumda tek bir "eşittir" =işareti (her iki eşittir işareti ==eşitlik olarak kabul edilmiş gibi görünse de) operatör de). Böylece, bu başarısız olur (sessizce):

$ 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

... ancak alanı ekleyin - ve her şey iyi görünüyor:

$ 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

Bir bash kabuğu örneği verebilir misiniz ((A || B) && C)?
jww


Bu gerçekten bir cevap için yararlı değildir, çünkü komutu bir köşeli varsa, örneğin köşeli parantez içine nasıl tamamen dahil edeceğinizi göstermez.
Timothy Swan

5

[: too many argumentsVeya [: a: binary operator expectedhatalarını alabileceğiniz başka bir senaryo, tüm bağımsız değişkenleri test etmeye çalışmanızdır"$@"

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

foo.shVeya öğesini ararsanız düzgün çalışır foo.sh arg1. Ancak foo.sh arg1 arg2, gibi birden çok argüman iletirseniz hatalar alırsınız. Bunun nedeni [ -z arg1 arg2 ], geçerli bir sözdizimi olmayan genişletilmiş olmasıdır.

Argümanların varlığını kontrol etmenin doğru yolu [ "$#" -eq 0 ]. ( $#bağımsız değişkenlerin sayısıdır).


2

Bazı zamanlar Klavyeye yanlışlıkla dokunursanız ve bir boşluk kaldırırsanız.

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

Bu hata mesajını tetikler. ']' Öncesinde boşluk olması gerektiğini unutmayın.


1
Bunun gibi farklı bir sözdizimi hatasıyla sonuçlandığını düşünüyorum: satır 21: [: eksik `] '
Joe Holloway

1

Senaryolarımda da aynı sorun vardı. Ama bazı değişiklikler yaptığımda benim için çalıştı. Bunu beğendim: -

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

bu şekilde sorunumu çözdüm. Umarım bu da sana yardımcı olur.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.