Nawiasy w warunku if: dlaczego dostaję błędy składniowe bez białych znaków?

17

Korzystam z poniższego skryptu, aby przejść dwa dni wstecz, gdy skrypt uruchamia się o dwa dni w roku, a także sprawdzam pierwszy i drugi dzień każdego miesiąca i cofam się o dwa dni wstecz.

if [$month="01"] && [$day="01"];
then
    date="$last_month/$yes_day/$last_year"
      fulldate="$last_month/$yes_day/$last_year"
else
if [$month="01"] && [$day="02"];
then
         date="$last_month/$yes_day/$last_year"
      fulldate="$last_month/$yes_day/$last_year"
else
   if [ $day = "01" ];
then
    date="$last_month/$yes_day/$year"
            fulldate="$year$last_month$yes_day"
else
        if [ $day = "02" ];
then
    date="$last_month/$yes_day/$year"
        fulldate="$year$last_month$yes_day"
else
    date="$month/$yes_day/$year"
        fulldate="$year$month$yes_day"
                fi
               fi
              fi
fi

Ale mój zły otrzymuję poniższy komunikat o błędzie

Etime_script.sh: line 19: [06=01]: command not found
Etime_script.sh: line 24: [06=01]: command not found
Kumar1
źródło
1
Podane odpowiedzi są poprawne; po tym potrzebujesz spacji [. Dodatkowo spójrz na elifoświadczenie; pomoże ci to posprzątać. Również średniki po instrukcjach if nie są konieczne, ale również nie są niepoprawne, po prostu dziwne.
Shawn J. Goff,
@ ShawnJ.Goff Są one konieczne, jeśli połączysz następną linię ( if [ ... ]; then), więc nie jest to takie niezwykłe.
goldilocks
@Goldilocks, tak, to mój ulubiony styl. Powodem tego jest niezwykły, ponieważ on tego nie robi.
Shawn J. Goff,

Odpowiedzi:

27

[nie jest metaznakiem ani operatorem sterującym (nawet słowem zastrzeżonym; to samo dla ]), dlatego potrzebuje wokół niego spacji. W przeciwnym razie powłoka „widzi” polecenie [01=01]zamiast polecenia [z oddzielnych parametrów 01, =, 01i ]. Każdy operator i operand musi być osobnym argumentem dla [polecenia, więc białe znaki są konieczne również wokół operatorów.

if [ "$month" = "01" ]

[$month="01"]to wzór wieloznaczny pasujący do dowolnego ze znaków w $monthlub "01. Jeśli nic nie pasuje, zostaje sam.

Jeśli po nawiasie zamykającym jest średnik, nie potrzebujesz przed nim spacji, ponieważ średnik jest zawsze częścią oddzielnego tokena.

if [ "$month" = "01" ]; then

To samo dotyczy składni podwójnych nawiasów bash (oraz ksh i zsh).

Więcej niż jeden warunek

Istnieją dwa sposoby łączenia warunków:

  1. w ciągu [

  2. z osobnymi [poleceniami w połączeniu z &&lub||

Grupowanie w nawiasach jest prawdopodobnie łatwiejsze [.

if [ "$month" = "01" -a "$day" = "01" ] # -a for and, -o for or

if [ "$month" = "01" ] && [ "$day" = "01" ]

Pierwszego należy unikać, ponieważ jest zawodny (spróbuj na przykład z month='!'). Problemów z dziwną zawartością zmiennych można uniknąć, używając najpierw bezpiecznego ciągu (jeśli taki istnieje); lub używając [[/ ]]zamiast [/ ]:

if [ "01" = "$month" -a "01" = "$day" ]
Hauke ​​Laging
źródło
Jak możemy dopasować dwa warunki w if, np. Wartość miesiąca == wartość dnia, jeśli [$ miesiąc = „01”] && [$ dzień = „01”];
oczekuję
@AshokSanganahalli Rozszerzyłem swoją odpowiedź.
Hauke ​​Laging
1
[kiedy -a/ -onie są używane, zawsze jest niezawodne w przypadku powłok zgodnych z POSIX. Korzystanie z -a/-oponad nie ma żadnej przewagi &&/||. Zdecydowanie odradzałbym jego użycie. Zauważ, że [[to nie jest POSIX.
Stéphane Chazelas
4

Inny sposób, aby to napisać:

case $month:$day in
  (01:0[12])
    date="$last_month/$yes_day/$last_year"
    fulldate="$last_month/$yes_day/$last_year"
    ;;
  (*:0[12])
    date="$last_month/$yes_day/$year"
    fulldate="$year$last_month$yes_day"
    ;;
  (*)
    date="$month/$yes_day/$year"
    fulldate="$year$month$yes_day"
esac
Stéphane Chazelas
źródło
1
+1 za casewyciąg. Jeśli masz więcej niż jeden elif, prawdopodobnie powinieneś używać case.
HalosGhost
-1

Oto twoja odpowiedź:

if [ $var1 == $var2 ];
 then
    echo "bla bla"
fi

Musisz więc wstawić „spację” między nawias kwadratowy a zmienną / wartością.

Neven
źródło
nie zgaduję, ponieważ ponieważ poprosiłem skrypt o przejście dwa dni wstecz, gdy skrypt uruchamia się na początku dwóch dni w roku, a także sprawdzanie pierwszego i drugiego dnia każdego miesiąca i przejście o dwa dni wstecz oznacza tutaj, jeśli [$ miesiąc = "01"] && [$ day = "01"] przypuszczamy, że dopasujemy miesiąc „01” i pierwszy dzień „01” prawda, przejdź do tego lub przejdź do innego warunku
Kumar1,
1
@AshokSanganahalli: Nie wiem, w jaki sposób jest to powiązane, ale twój warunek JEŻELI nie działa, ponieważ nie masz „pustej przestrzeni” między nawiasami kwadratowymi a wartością
Neven
@AshokSanganahalli Zwykle nie jest dobrym pomysłem dla osób na twoim poziomie umiejętności kwestionowanie poprawek od osób z wyraźnie lepszym zrozumieniem bez przynajmniej próby podpowiedzi. Gdyby twoje domysły były słuszne, nie musiałbyś tutaj pytać, prawda?
Hauke ​​Laging
4
-1 dla zmiennych niecytowanych i użycia ==zamiast standardowych =.
Stéphane Chazelas
2
Pytanie nie jest oznaczone bash. Operatorem porównania równości w standardowej komendzie [akatest jest =. [jeśli chodzi o testy, to nie wykonuje żadnego zadania, więc nie trzeba jednoznacznie określać. Niektóre [implementacje obsługują ==rozszerzenie jako standard, ale nie wszystkie. The Bourne shell'S, ash's, posh' s [s lub /bin/[niektórych systemach, na przykład nie. ==został dodany przez ksh, przypuszczam, że dla spójności z tym samym operatorem w jego nowej (( ... ))konstrukcji (która ma zarówno = i ==, ale nie ma standardu)
Stéphane Chazelas