jak sprawdzić, czy 1 $ i 2 $ są zerowe?

40

Używam skryptu, który przekazuje argument ciągu i chcę to zrobić, jeśli instrukcja pokazana jest poniżej:

if [ $1 != '' ] && [ $2 != '' ]
then 
    do something.....

ale to pokazało Error too many argument. Czemu?

taymindis Woon
źródło
Powinieneś podać 1. polecenie, które wywołujesz skrypt i 2. pełne wyjście.
Lucio,
2
Powinieneś użyć [[ ]]. W przeciwnym razie musisz podać swoje zmienne.
Christophe De Troyer
Gdyby 1 $ nie istniał, wówczas 2 $ stałoby się 1 $, co sprawia, że ​​test 1 $ i 2 $ są zerowe, wydaje się nieistotne.
WinEunuuchs2Unix,
@ WinEunuuchs2Unix Niekoniecznie nie ma znaczenia - w niektórych przypadkach chcesz się upewnić, że w argumentach jest coś zamiast pustego lub pustego łańcucha. $1może zostać ustawiony lub zerowany przez użytkownika skryptu. Rozważ tę sekwencję poleceń: $ set '' barwówczas echo "x${1}x";obie zmienne są ustawione, ale jedna z nich jest pusta.
Sergiy Kolodyazhnyy

Odpowiedzi:

55

Spróbuj użyć testu -z:

if [ -z "$1" ] && [ -z "$2" ]

Od człowieka bash:

-z string
   True if the length of string is zero.
Sylvain Pineau
źródło
Mi to pasuje!
pengisgood,
interesujące jest to, że najczęściej głosowana i akceptowana odpowiedź w rzeczywistości nie odpowiada na zadane pytanie.
mehmet
Podczas pisania przenośnych skryptów powłoki flaga ta powinna być używana ostrożnie, ponieważ w niektórych komercyjnych Uniksach flaga ta jest wadliwa. Zobacz moją odpowiedź dla połączonych źródeł.
Sergiy Kolodyazhnyy
14

Ponieważ jest to oznaczone bash, polecam użyć rozszerzonej konstrukcji testowej ( [[...]]) i zapomnieć o cudzysłowach:

if [[ -z $1 && -z $2 ]]; then
...

O ile nie wybierasz shkompatybilności / POSIX, nie ma powodu, aby nie używać [[ ]].

muru
źródło
3

Działa również:

if [ "$1" == "" && "$2" == ""]; then
    echo NULL
fi
Avinash Raj
źródło
Pozostałe &&klasyczne separatory poleceń są niedozwolone test. Zamiast tego musisz użyć innych konstrukcji testowych (jak -amyślę)
muru
3

W przypadku starej wersji odpowiedzi zobacz drugą część tej odpowiedzi. Jeśli chcesz wiedzieć o szczegółach, czytaj dalej

Przyczyna problemu

W samym pytaniu podano, że OP widzi too many arguments error, co bashnie wydaje się , gdy jest testowane :

$ [ $1 != '' ] && [ $2 != '' ]
bash: [: !=: unary operator expected

Z /bin/shktórym w rzeczywistości jest symlinkowany /bin/dashna Ubuntu, błąd zgłaszany w następujący sposób:

$ sh
$ [ $1 != '' ] && [ $2 != '' ]
sh: 1: [: !=: unexpected operator

A samodzielny /bin/testrównież:

$ /usr/bin/test $1 != ''  
/usr/bin/test: missing argument after ‘’

Sidenote: Jeśli zastanawiasz się, co to jest /usr/bin/testi dlaczego używam bashi sh, to powinniście wiedzieć, że [jest alias dla testkomendy, która występuje także jako samodzielny plik wykonywalny lub częściej - jak skorupy wbudowany w którym to, co każda powłoka użyje pierwszy . Jeśli chodzi o ifinstrukcje, operują one na statusach wyjściowych poleceń, stąd polecenia [i testsą, a wszystko inne jest argumentem tych poleceń - niewłaściwa kolejność tych argumentów wiersza poleceń prowadzi do błędów.

Powrót do tematu: nie jest jasne, w jaki sposób OP otrzymał niepowiązany błąd. Jednak we wszystkich 3 przypadkach problem jest taki sam - zmienna nieuzbrojona będzie traktowana jako pusta, dlatego to, co powłoka widzi z tymi niecytowanymi zmiennymi, to

[ != '' ]

który łamie składnię, która testrozumie. Pamiętasz, co powiedziałem o niewłaściwej kolejności argumentów wiersza poleceń? Dlatego dlaczego cytowanie jest ważne. Włączmy dane diagnostyczne i zobaczmy, co wykonuje powłoka:

$ set -x
# throws error
$ [ $1 != '' ] && [ $2 != '' ] 
+ '[' '!=' '' ']'
bash: [: !=: unary operator expected
# no error
$ [ "$1" != '' ] && [ "$2" != '' ] || echo null vars
+ '[' '' '!=' '' ']'
+ echo null vars
null vars

Lepszy sposób testowania nieuzbrojonych zmiennych

Bardzo częstym podejściem jest:

 if [ "x$var1" == "x"  ] && [ "x$var2" == "x"  ];                                                                
 then
     echo "both variables are null"
 fi

Cytując Gillesa :

W ["x $ 1" = "x"] przedrostek x zapewnia, że ​​x "$ 1" nie może wyglądać jak operator, więc jedynym sposobem, w jaki powłoka może przeanalizować ten test, jest traktowanie = jako operatora binarnego.

Prawdopodobnie powinno to być dość przenośne, ponieważ widziałem je w /bin/shskryptach. Można go również łączyć jak w

if [ "x${var1}${var2}" == "x" ]; then
    ...
fi

Oczywiście moglibyśmy użyć -zflagi, jednak według badań niektórych pocisków, szczególnie ksh88 (według Stephane Chazelas ), flaga ta jest wadliwa.

Zobacz też

Sergiy Kolodyazhnyy
źródło
+1 za bardzo interesujące podejście.
WinEunuuchs2Unix,
@ WinEunuuchs2Unix Edytowane, aby uczynić go jeszcze bardziej interesującym :)
Sergiy Kolodyazhnyy
1

Myślę, że tytuł postu jest niepoprawny, ponieważ celem wiadomości było sprawdzenie, czy 1 i 2 USD nie są zerowe. W podanym przykładzie brakowało podwójnych cudzysłowów w 1 USD i 2 USD do pracy. Zmienne muszą być podwójnie cytowane, aby można je było rozwinąć podczas porównywania ciągów. Ale sprawdzenie, czy istnieje 1 USD i 2 USD, jest tym samym, co sprawdzenie, czy 2 USD istnieje, ponieważ nie może istnieć, jeśli 1 USD nie istnieje. W tym przypadku nie jest również potrzebne polecenie „if”, ponieważ „test” zwraca wartość true / false i używa „&&” jako „następnie”, jeśli return wynosi 0 / true:

[ "$2" != '' ] && commands...

Prostsze, z -n (niezerową):

[ -n "$2" ] && commands...

Aby „sprawdzić, czy 1 $ i 2 $ są zerowe” byłoby to samo, co sprawdzenie, czy nie ma parametru:

[ $# -eq 0 ] && commands...
Guariba Som
źródło