syntax error near unexpected token переводится как «синтаксическая ошибка рядом с неожиданным токеном». Bash разбирает строку целиком до того, как что-то запустить, и встретил слово или символ, которого в этом месте быть не может. Поэтому команда не выполнилась вовсе — даже её начало. В русской локали то же сообщение звучит как «синтаксическая ошибка рядом с неожиданным маркером»:
bash: синтаксическая ошибка рядом с неожиданным маркером «(»
Главная подсказка — токен в кавычках в конце сообщения. Он почти всегда сразу называет причину:
| Токен в сообщении | Что случилось |
|---|---|
`(' | скобки в имени файла или аргументе без кавычек |
`newline' | в команде остались угловые скобки из инструкции: <url> |
`$'do\r'', `$'\r'' | файл сохранён с переводами строк Windows |
`fi', `done', `echo' | в if пропущен then, в for или while пропущен do |
`else', `}' | пустой блок: между then и else или в { } нет ни одной команды |
| кусок кода на другом языке | bash запустил файл Python или другого языка |
Ниже каждый случай разобран на настоящем выводе: Debian 12, bash 5.2.15.
Bash сдаётся ниже, чем ошибся ты
Как читать сообщение и проверить скрипт без запуска
Сообщение из скрипта состоит из двух строк: в первой файл, номер строки и токен, во второй — сама строка, на которой bash остановился. Чтобы найти все такие ошибки и ничего при этом не выполнить, запусти проверку синтаксиса bash -n:
bash -n list.sh
list.sh: line 2: syntax error near unexpected token `$'do\r''
list.sh: line 2: `for f in *.txt; do'
Номер строки показывает, где bash сдался, а не где ты ошибся. Если там стоит закрывающее слово — fi, done, } или else, — смотри на начало этого блока выше.
Токен (: скобки без кавычек
Круглые скобки для bash — часть синтаксиса: ими объявляют функции, массивы и подоболочки. Имя файла со скобками, набранное как есть, ломает строку:
cp report (1).txt archive/
bash: syntax error near unexpected token `('
Возьми имя в кавычки — или нажми Tab, и bash сам экранирует скобки обратной косой чертой:
cp "report (1).txt" archive/ && ls archive
report (1).txt
То же касается других служебных символов в аргументах: ;, &, |, <, >. Имена, которые скачали браузеры и мессенджеры, — photo (2).jpg, отчёт (копия).docx — безопаснее всегда брать в кавычки.
Токен newline: угловые скобки из инструкции
В документации заглушки часто пишут в угловых скобках: «выполни git clone <url>». Если вставить команду как есть, bash читает < как перенаправление ввода и ждёт после > имя файла, а там конец строки:
git clone <url>
ssh-copy-id <user>@<server>
bash: syntax error near unexpected token `newline'
bash: syntax error near unexpected token `newline'
Угловые скобки нужно заменить вместе с содержимым: git clone https://github.com/user/project.git, ssh-copy-id dev@203.0.113.10.
Тот же токен выдаёт скачанный скрипт, вместо которого сервер прислал HTML-страницу ошибки. Её первая строка <!DOCTYPE html> для bash — перенаправления без имени файла:
bash install.sh
install.sh: line 1: syntax error near unexpected token `newline'
install.sh: line 1: `<!DOCTYPE html>'
Открой файл через head install.sh, прежде чем запускать: если там HTML, адрес для скачивания неверный.
Токен $'do\r': файл из Windows
Редакторы Windows заканчивают строки двумя символами, \r\n, а bash ждёт один \n. Лишний \r прилипает к последнему слову строки, и слово do превращается в do\r, которого bash не знает. Скрипт list.sh, сохранённый в Windows:
bash list.sh
list.sh: line 2: syntax error near unexpected token `$'do\r''
list.sh: line 2: `for f in *.txt; do'
Запись $'do\r' — это bash показывает невидимый символ. Сам файл выдаёт file, а cat -A показывает \r как ^M в конце строк:
file list.sh
cat -A list.sh
list.sh: Bourne-Again shell script, ASCII text executable, with CRLF line terminators
#!/bin/bash^M$
for f in *.txt; do^M$
echo "$f"^M$
done^M$
Удали \r и запусти снова:
sed -i 's/\r$//' list.sh && bash list.sh
report (1).txt
То же делает утилита dos2unix. Чтобы ошибка не вернулась, включи в редакторе окончания строк LF; в VS Code переключатель CRLF/LF стоит в строке состояния. Если такой файл запустить как ./list.sh, ошибка будет другой — про интерпретатор /bin/bash^M, она разобрана в статье про bash-скрипты.
Токены fi, done, echo: пропущены then или do
В if после условия обязательно then, в for и while перед телом — do. Если их забыть, bash замечает это не сразу. Скрипт nothen.sh без then:
bash nothen.sh
nothen.sh: line 4: syntax error near unexpected token `fi'
nothen.sh: line 4: `fi'
Ошибка во второй строке, а bash жалуется на четвёртую: до самого fi он считал, что условие продолжается. С for без do сообщение называет первую команду тела:
bash nodo.sh
nodo.sh: line 3: syntax error near unexpected token `echo'
nodo.sh: line 3: ` echo "$f"'
Если then или do стоит на той же строке, что условие, перед ним нужна точка с запятой: if [ -f data.txt ]; then, for f in *.txt; do.
Токены else и }: пустой блок
Bash не разрешает блоки без единой команды, а комментарий командой не считается. Заготовка с # TODO внутри then падает на else:
bash emptythen.sh
emptythen.sh: line 4: syntax error near unexpected token `else'
emptythen.sh: line 4: `else'
Пустая функция cleanup() { } — на закрывающей скобке:
bash emptyfunc.sh
emptyfunc.sh: line 3: syntax error near unexpected token `}'
emptyfunc.sh: line 3: `}'
Пустое место заполняет команда :. Она ничего не делает и всегда завершается успешно: : # TODO в ветке then и cleanup() { :; } для функции. После такой правки оба скрипта отрабатывают без ошибок.
Кусок кода в токене: bash запустил файл Python
Если в сообщении вместо служебного слова виден кусок кода, скорее всего, bash выполняет файл, написанный на другом языке. Файл hello.py без первой строки #!/usr/bin/env python3 запустили как ./hello.py, и система отдала его bash:
./hello.py
./hello.py: line 1: import: command not found
./hello.py: line 2: syntax error near unexpected token `"Привет",'
./hello.py: line 2: `print("Привет", sys.argv)'
Запускай файл его интерпретатором — или добавь shebang первой строкой, чтобы работал и ./hello.py:
python3 hello.py
Привет ['hello.py']
sh вместо bash: Syntax error: ”(” unexpected
В Debian и Ubuntu команда sh — это dash, более простая оболочка. Синтаксиса bash — слова function, массивов ( ), [[ ]] — она не знает, и её сообщение выглядит иначе:
sh greet.sh
sh arr.sh
bash greet.sh
greet.sh: 2: Syntax error: "(" unexpected
arr.sh: 2: Syntax error: "(" unexpected
Привет, Анна
Тот же greet.sh, запущенный через bash, работает. Скрипт с конструкциями bash запускай через bash script.sh или как ./script.sh с первой строкой #!/bin/bash. Подробнее о том, чем это грозит в cron, — в статье про crontab.
ShellCheck показывает, где ошибка на самом деле
bash -n называет место, где разбор сломался, а ShellCheck — место, где ты ошибся. На том же скрипте без then:
shellcheck nothen.sh
In nothen.sh line 2:
if [ -f data.txt ]
^-- SC1049 (error): Did you forget the 'then' for this 'if'?
^-- SC1073 (error): Couldn't parse this if expression. Fix to allow more checks.
In nothen.sh line 4:
fi
^-- SC1050 (error): Expected 'then'.
^-- SC1072 (error): Unexpected keyword/token. Fix any mentioned problems and try again.
For more information:
https://www.shellcheck.net/wiki/SC1049 -- Did you forget the 'then' for thi...
https://www.shellcheck.net/wiki/SC1050 -- Expected 'then'.
https://www.shellcheck.net/wiki/SC1072 -- Unexpected keyword/token. Fix any...
Первая же подсказка указывает на вторую строку и прямо называет пропущенное слово. В Debian и Ubuntu ShellCheck ставится пакетом shellcheck, есть и расширение для VS Code, которое подчёркивает такие ошибки прямо при наборе.
Частые вопросы
Как перевести syntax error near unexpected token
«Синтаксическая ошибка рядом с неожиданным токеном». Токен — слово или символ, на котором bash остановился; он указан в кавычках в конце сообщения. В русской локали bash пишет «синтаксическая ошибка рядом с неожиданным маркером».
Почему номер строки не совпадает с местом ошибки
Bash сообщает строку, где понял, что разбор невозможен. Незакрытый блок или пропущенный then он замечает только на следующем служебном слове, поэтому смотри на несколько строк выше указанной или запусти ShellCheck.
Как проверить скрипт, не запуская его
bash -n script.sh разбирает файл и сообщает о синтаксических ошибках, ничего не выполняя. ShellCheck делает то же и вдобавок находит ловушки вроде переменных без кавычек.