Помилка синтаксису біля несподіваного маркера `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 для коду С). Я також рекомендую прочитати обов'язково: 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

якщо список; потім список; [список elif; потім список; ] ... [інший список;] fi

Список if виконується. Якщо його вихідний стан дорівнює нулю, тоді виконується список. В іншому випадку кожен список elif виконується по черзі, і якщо його статус виходу дорівнює нулю, виконується відповідний список списку і команда завершується. В іншому випадку список інших виконується, якщо він присутній. Статус виходу - це стан виходу останньої виконаної команди або нульовий, якщо умова не перевірена істинною.

Вам не вистачає ;

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.