Синтаксическая ошибка рядом с неожиданным токеном `fi`

17

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

Когда я запускаю скрипт, я получаю сообщение об ошибке:

Синтаксическая ошибка рядом с неожиданным токеном fi

Я пришел к выводу, что моя проблема заключается в моем ifзаявлении, сделав ifкомментарии к своим заявлениям и добавив, echo "$NAME"какие имена отображаются в /etc/.

Когда я делаю изменения, удаления #от ifи fiдобавить #к wc -c "$NAME", я получаю ошибку синтаксиса я перечислил выше. Я добавил ;между ]тем. Я также перешел thenна следующую строку без разрешения.

#!/bin/bash
for NAME in /etc/*
do

     if [ -r "$NAME" -af "$NAME" ] then
          wc -c "$NAME"
     fi
done
Кристина Гусман
источник
9
Всякий раз, когда у вас возникает ошибка синтаксиса оболочки, первым хорошим шагом будет вырезать и вставить свой код в shellcheck.net и исправить обнаруженные ошибки. Если у вас возникли проблемы с пониманием его сообщений, тогда приходите сюда и спрашивайте.
John1024
2
Что это -afдолжно делать?
ilkkachu
Спасибо за этот сайт @ John1024, он был самым полезным, я добавил его в закладки для дальнейшего использования.
Кристина Гусман
1
@ChristinaAGuzman В таком случае -aявляется избыточным, потому что условие уже включено в -f. --- В любом случае несколько условий внутри [ ](эта команда также доступна как test) должны быть объединены с использованием логических операторов, таких как -a(и) или -o(или), но, как было предложено в ответе ниже, лучше использовать несколько команд [ ]( test) и присоединиться их используя операторы оболочки, такие как &&или ||.
Пабук
2
Кристина, как указывалось @ John1024, shellcheck.net очень четко показывает некоторый синтаксис или даже более глубокие ошибки (как lint делает для кода C). Я также рекомендую прочитать: mywiki.wooledge.org/BashPitfalls (прочитайте его хотя бы один раз!) И mywiki.wooledge.org/BashFAQ, а также mywiki.wooledge.org/BashGuide хорошо читать.
Оливье Дюлак

Ответы:

46

Ключевые слова , как if, then, else, fi, for, caseи так далее должны быть в месте , где оболочка ожидает имя команды. В противном случае они рассматриваются как обычные слова. Например,

echo if

просто печатает if, он не запускает условную инструкцию.

Таким образом, в строке

if [ -r "$NAME" -af "$NAME" ] then

слово thenявляется аргументом команды [(на которую она будет жаловаться, если она когда-либо будет запущена). Оболочка продолжает искать thenи находит fiкомандную позицию. Поскольку он ifвсе еще ищет его then, fiон неожиданный, есть синтаксическая ошибка.

Перед thenэтим нужно поставить терминатор команды, чтобы он распознавался как ключевое слово. Наиболее распространенный терминатор команд - это разрыв строки, но до thenэтого обычно используют точку с запятой (что имеет то же значение, что и разрыв строки).

if [ -r "$NAME" -af "$NAME" ]; then

или

if [ -r "$NAME" -af "$NAME" ]
then

Как только вы исправите это, вы получите еще одну ошибку от команды, [потому что она не понимает -af. Вы, вероятно, имели в виду

if [ -r "$NAME" -a -f "$NAME" ]; then

Хотя тестовые команды выглядят как опции, вы не можете связать их так. Они - операторы [команды, и каждый из них должен быть отдельным словом (как это делают [и ]).

Кстати, хотя [ -r "$NAME" -a -f "$NAME" ]работает, я рекомендую писать либо

[ -r "$NAME" ] && [ -f "$NAME" ]

или

[[ -r $NAME && -f $NAME ]]

Лучше сохранять [ … ]условия простыми, потому что [команда не может легко отличить операторы от операндов. Если $NAMEвыглядит как оператор и появляется в позиции, где оператор действителен, он может быть проанализирован как оператор. Это не произойдет в простых случаях, представленных в этом ответе, но более сложные случаи могут быть рискованными. Запись этого с отдельными вызовами [и использованием логических операторов оболочки позволяет избежать этой проблемы.

Второй синтаксис использует [[ … ]]условную конструкцию, которая существует в bash (и ksh и zsh, но не просто sh). Эта конструкция специальный синтаксис, в то время как [обрабатывается , как и любой другой команды, таким образом , вы можете использовать такие вещи , как &&внутри , так и вам не нужно цитировать переменных , кроме аргументов некоторых строковых операторов ( =, ==, !=, =~) (см Когда двойные кавычки необходимо ? для более подробной информации).

Жиль "ТАК - прекрати быть злым"
источник
Обратите внимание, что if [[ 1 ]] then [[ 2 ]] fiработает в ksh, pdksh и zsh. if(:)then(:)fiработает во всех снарядах.
Стефан
12

Посмотрите, что изменилось следующим образом

if [-r "$ NAME" -a -f "$ NAME"] ; тогда
# ^^^^^ ^
     wc -c "$ NAME"
фи

Если вы хотите удалить все команды в блоке if, вам по крайней мере нужно добавить в него двоеточие, например

if [ -r "$NAME" -a -f "$NAME" ]; then
    :
fi

или однострочная версия

if [ -r "$NAME" -a -f "$NAME" ]; then :; fi

Брюс
источник
2

Другие уже указали, но если вы ищете официальную ссылку, то RTM

если список; затем список; [список элифов; затем список; ] ... [еще список;] фи

Список if выполнен. Если его статус выхода равен нулю, то список выполняется. В противном случае каждый список elif выполняется по очереди, и если его состояние выхода равно нулю, выполняется соответствующий thenlist, и команда завершается. В противном случае, список else выполняется, если присутствует. Состояние выхода - это состояние выхода последней выполненной команды или ноль, если ни одно из условий не проверено как истинное.

Вы скучаете по ;

И синтаксис для listописан вman test

Kashyap
источник