Скобки в условии if: почему я получаю синтаксические ошибки без пробелов?

17

Я использую приведенный ниже сценарий для перемещения на два дня назад, когда сценарий запускается в начале двух дней в году, а также для проверки первого и второго дней каждого месяца и перехода на два дня назад.

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

Но мой плохой получаю сообщение об ошибке ниже

Etime_script.sh: line 19: [06=01]: command not found
Etime_script.sh: line 24: [06=01]: command not found
Kumar1
источник
1
Данные ответы верны; вам нужно пробел после [. Кроме того, посмотрите на elifутверждение; это поможет вам очистить вещи. Кроме того, точки с запятой после операторов if не являются необходимыми, но также не являются неправильными, просто странными.
Шон Дж. Гофф
@ ShawnJ.Goff Они необходимы, если вы объединяете следующую строку ( if [ ... ]; then), так что не так уж необычно.
Златовласка
@goldilocks, да, это мой любимый стиль. Причина в том, что он необычный, потому что он этого не делает.
Шон Дж. Гофф,

Ответы:

27

[не является ни метасимволом, ни оператором управления (даже не зарезервированным словом; то же самое для ]), поэтому ему необходимо пространство вокруг него. В противном случае оболочка «видит» команду [01=01]вместо команды [с отдельными параметрами 01, =, 01, и ]. Каждый оператор и операнд должен быть отдельным аргументом [команды, поэтому пробел также необходим вокруг операторов.

if [ "$month" = "01" ]

[$month="01"]шаблон подстановки, соответствующий любому из символов в $monthили "01. Если это ничего не соответствует, это остается один.

Если после закрывающей скобки стоит точка с запятой, перед ней не требуется пробел, потому что точка с запятой всегда является частью отдельного токена.

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

То же самое касается синтаксиса двойных скобок bash (и ksh, и zsh).

Более одного условия

Есть два способа объединить условия:

  1. в [

  2. с отдельными [командами в сочетании с &&или||

Группировать с помощью скобок, вероятно, легче внутри [.

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

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

Первого следует избегать, так как он ненадежен (попробуйте, например, с month='!'). Проблем со странным переменным содержимым можно избежать, если сначала использовать безопасную строку (если она есть); или используя [[/ ]]вместо [/ ]:

if [ "01" = "$month" -a "01" = "$day" ]
Хауке Лагинг
источник
Как мы можем сопоставить два условия в if, например, значение месяца == значение дня if [$ month = "01"] && [$ day = "01"]; Я ожидаю 01 && 01 true, затем напечатайте ниже условия или перейдите к заявлению else
Kumar1
@AshokSanganahalli Я расширил свой ответ.
Хауке Лагинг
1
[когда -a/ -oне используется всегда надежно с POSIX-совместимыми оболочками. Там нет никакого преимущества в использовании -a/-oболее &&/||. Я определенно препятствовал бы его использованию. Обратите внимание, что [[это не POSIX.
Стефан Шазелас
4

Еще один способ написать это:

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
Стефан Шазелас
источник
1
+1 за caseутверждение. Если у вас есть более одного elif, вы, вероятно, должны использовать case.
HalosGhost
-1

Итак, это ваш ответ:

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

Таким образом, вы должны поставить «пробел» между квадратной скобкой и переменной / значением.

Neven
источник
нет, я Угадаю, потому что, как я просил скрипт переместить два дня назад, когда скрипт запускается в начале двух дней года, а также проверить первый и второй дни каждого месяца и переместить два дня назад, значит здесь, если [$ month = "01"] && [$ day = "01"] мы полагаем, что для месяца "01" и первого дня "01" верно значение true, затем перейти или перейти в другое условие
Kumar1
1
@AshokSanganahalli: я не знаю, как это связано, но ваше условие IF не работает, потому что у вас нет «пробела» между квадратными скобками и значением
Neven
@AshokSanganahalli Обычно людям с вашим уровнем квалификации не очень хорошая идея оспаривать исправления от людей с явно лучшим пониманием, по крайней мере, не пытаясь дать подсказку. Если бы ваши догадки были верны, то вам не пришлось бы спрашивать здесь, не так ли?
Хауке Лагинг
4
-1 для переменных без кавычек и использования ==вместо стандартных =.
Стефан Шазелас
2
Вопрос не помечен как bash. Оператор сравнения равенства в стандартной команде [akatest есть =. [если для тестов, это не делает никакого назначения, поэтому нет необходимости устранять неоднозначность. Некоторые [реализации поддерживают ==как расширение над стандартом, но не все. Оболочки Борна, ash«s, posh» s [s или /bin/[некоторых систем , например нет. ==было добавлено ksh, я полагаю, для согласованности с тем же оператором в его новой (( ... ))конструкции (которая имеет оба = и ==, но это не стандарт)
Стефан Шазелас