Вы когда-нибудь видели сообщение «Ошибка синтаксиса рядом с неожиданным токеном» при запуске одного из ваших скриптов Bash?

В этом руководстве я покажу вам, почему возникает эта ошибка и как ее исправить.

«Bash Syntax Error Near Unexpected Token» — это ошибка синтаксиса Bash, которая сообщает о неправильном синтаксисе в вашем скрипте или команде. В скрипте Bash может быть много ошибок, которые могут привести к этой ошибке. Некоторые распространенные причины — отсутствие пробелов рядом с командами и отсутствие экранирования для символов, имеющих особое значение для оболочки Bash.

Поиск синтаксической ошибки, сообщаемой при выполнении скрипта, не всегда прост. Этот процесс часто требует многократного изменения и повторного тестирования скрипта.

Чтобы облегчить вам жизнь, я проанализировал различные сценарии, в которых может возникнуть эта синтаксическая ошибка. Для каждого сценария я покажу вам скрипт или команду с ошибкой и исправление, которое вам нужно применить для решения проблемы.

Один подход к исправлению этой ошибки в нескольких сценариях

Изучив приведенные ниже примеры, вы узнаете, как определить причину этой ошибки и как ее исправить.

В некоторых примерах я покажу вам, как исправить эту ошибку, если она возникает при выполнении одной команды в оболочке Bash.

В других примерах мы рассмотрим скрипты Bash, выполнение которых завершается ошибкой «unexpected token».

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

Чтобы понять, как исправить ошибку в скрипте, может потребоваться немного больше времени, и для этого я буду использовать следующий процесс из 5 шагов:

  1. Запустите скрипт, содержащий синтаксическую ошибку.
  2. Обратите внимание на строку, упомянутую в ошибке Bash.
  3. Выполните строку с ошибкой в ​​оболочке Bash, чтобы быстро найти ошибку (без необходимости изменять скрипт и перезапускать его несколько раз).
  4. Обновите свой скрипт, добавив правильную строку кода.
  5. Подтвердите, что скрипт работает.

Давайте рассмотрим первый сценарий.

Syntax Error Near Unexpected Token ‘(‘

Допустим, в моей системе Linux есть следующий файл:

-rw-r--r--  1 ec2-user ec2-user   28 Jun 28 22:29 report(july).csv

И я хочу переименовать его в report_july.csv.

Я могу использовать следующую команду, верно?

mv report(july).csv report_july.csv

При запуске появляется следующая ошибка:

-bash: syntax error near unexpected token `('

Но почему?

Потому что скобки () используются в Bash для создания подоболочки. Другими словами, это специальные символы.

А специальные символы Bash необходимо экранировать, если они используются как обычные символы в команде. Обратная косая черта используется для экранирования символов.

Я обновлю команду, включив обратную косую черту перед обеими скобками:

mv report\(july\).csv report_july.csv

На этот раз ошибок нет:

-rw-r--r--   1 ec2-user ec2-user   28 Jun 28 22:29 report_july.csv

Урок 1: Не забывайте экранировать специальные символы Bash, когда вы используете их как обычные символы (литералы) в имени файла или строке в целом.

Мы исправили первую ошибку!

Syntax Error Near Unexpected Token Then (Пример 1)

А вот и второй сценарий.

Когда я запускаю следующий скрипт:

#!/bin/bash

DAY="Monday"

if[ $DAY == "Monday" ]; then
  echo "Today is Monday"
else
  echo "Today is not Monday"
fi

Я получаю следующую ошибку:

(localhost)$./unexpected_token.sh
./unexpected_token.sh: line 5: syntax error near unexpected token `then'
./unexpected_token.sh: line 5: `if[ $DAY == "Monday" ]; then'

Понимаете почему?

Ошибка вызвана отсутствием пробела между if и открывающейся квадратной скобкой ([).

Причина в следующем:

if — встроенная команда оболочки, и вы можете подумать, что используете if здесь. Но на самом деле оболочка видит if[, что это не известная ей команда.

Оболочка не знает, как с этим справиться, поскольку она не нашла его ранее, и останавливает скрипт с ошибкой, указанной выше.

Правильный сценарий:

#!/bin/bash

DAY="Monday"

if [ $DAY == "Monday" ]; then
  echo "Today is Monday"
else
  echo "Today is not Monday"
fi

Я только что добавил пробел между if и [, чтобы оболочка могла видеть команду if.

Вывод скрипта правильный:

(localhost)$./unexpected_token.sh
Today is Monday

Урок 2: Пробелы важны в Bash, поскольку они помогают оболочке идентифицировать каждую команду.

Syntax Error Near Unexpected Token Then (Пример 2)

При написании скриптов Bash, особенно в начале, часто можно допустить ошибки, подобные приведенной ниже:

(localhost)$ for i in {0..10} ; do echo $i ; then echo "Printing next number" ; done

Вот что вы получите, если запустите этот однострочный код:

-bash: syntax error near unexpected token `then'

Давайте выясним почему.

Синтаксис цикла for в Bash:

for VARIABLE in {0..10}
do
  echo command1
  echo command2
  echo commandN
done

И используя одну строку:

for VARIABLE in {0..10}; do echo command1; echo command2; echo commandN; done

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

Причина, по которой точки с запятой не требовались в первой версии скрипта, заключается в том, что символ новой строки также является разделителем команд.

Теперь вернемся к нашей ошибке…

Однострочник, который завершался ошибкой, содержит оператор then, который, как вы видите, не является частью структуры цикла for.

Ошибка сообщает нам:

  • Синтаксическая ошибка.
  • Знак «then» является неожиданным.

Давайте убедимся, что однострочный код работает нормально после удаления:

(localhost)$ for i in {0..10} ; do echo $i ; echo "Printing next number" ; done
0
Printing next number
1
Printing next number
2
Printing next number
3
Printing next number
4
Printing next number
5
Printing next number
6
Printing next number
7
Printing next number
8
Printing next number
9
Printing next number
10
Printing next number

Работает!

Урок 3: Если вы видите синтаксическую ошибку, проверьте, правильно ли вы используете циклы Bash или условные конструкции и не добавляете ли вы какие-либо операторы, которых там быть не должно.

Syntax Error Near Unexpected Token Done

Я создал простой скрипт, в котором оператор if вложен в цикл while. Это очень распространено в Bash.

#!/bin/bash

COUNTER=0
  
while true 
do
  if [ $COUNTER -eq 0 ]; then
    echo "Stopping the script..."
    exit 1
  done
fi

Этот скрипт может показаться нормальным, но когда я его запускаю, я получаю следующее:

./unexpected_token.sh: line 8: syntax error near unexpected token `done'
./unexpected_token.sh: line 8: `  done'

Почему?

Операторы done и fi правильно используются для закрытия цикла while и условного оператора if. Но они используются в неправильном порядке!

Оператор if вложен в цикл while, поэтому сначала мы должны закрыть оператор if, используя fi. А после этого мы можем закрыть цикл while, используя done.

Давайте попробуем сценарий:

(localhost)$./unexpected_token.sh 
Stopping the script...

Теперь все хорошо.

Урок 4: Вложенные циклы и условные операторы необходимо закрывать в том же порядке, в котором они открываются.

Syntax Error Near Unexpected Token fi

Давайте рассмотрим другой сценарий, в котором эта синтаксическая ошибка может возникнуть с токеном fi:

#!/bin/bash
  
for NAME in 'John' 'Mark' 'Kate'
do
    if [ "$NAME" == 'Mark' ] then
        echo 'Hello Mark!'
    fi
done

И вот что вы получите, если запустите его:

./unexpected_token.sh: line 7: syntax error near unexpected token `fi'
./unexpected_token.sh: line 7: `    fi'

В этом случае оболочка Bash распознает оператор if и поэтому ожидает после него then.

Как видите, так и есть, так в чем проблема?

Между командой [ ] (да… это команда) и оператором then нет разделителя команд.

Так в чем же решение?

Добавьте разделитель команд сразу после закрывающей квадратной скобки. Мы будем использовать точку с запятой (;) в качестве разделителя команд.

Наш сценарий становится таким:

#!/bin/bash
  
for NAME in 'John' 'Mark' 'Kate'
do
    if [ "$NAME" == 'Mark' ]; then
        echo 'Hello Mark!'
    fi
done

И если я его запущу, то получу правильный вывод:

(localhost)$./unexpected_token.sh 
Hello Mark!

Урок 5: Не забудьте указать разделители команд в скриптах Bash. Либо точка с запятой, либо новая строка.

Заключение

Теперь у вас есть все, что нужно, чтобы понять, что вызывает эту синтаксическую ошибку в ваших скриптах. Вы можете применить 5 уроков, которые я объяснил в этом руководстве, чтобы найти исправление.

Если у вас есть вопросы, пожалуйста, оставьте комментарий ниже.

Теперь предположим, что вы сохранили свой Bash-скрипт с помощью Windows.

А когда вы запускаете его в Linux, вы видите синтаксическую ошибку, которую не можете объяснить, поскольку скрипт выглядит для вас правильным.

Written by Иван Васильков

Системный администратор и DevOps с опытом 10+ лет.