Kesalahan sintaksis dekat token tak terduga `fi`


17

Saya tidak selalu menginginkan jawaban tetapi jika seseorang dapat mengarahkan saya ke beberapa literatur atau contoh. Saya ingin mencari tahu.

Ketika saya menjalankan skrip saya menerima kesalahan:

Kesalahan sintaksis dekat token yang tidak terduga fi

Saya telah menyimpulkan bahwa masalah saya ada dalam ifpernyataan saya dengan membuat ifkomentar pernyataan saya dan menambahkan echo "$NAME"yang menampilkan nama dalam/etc/ .

Ketika saya membuat perubahan, hapus #dari ifdan fidan tambahkan #ke wc -c "$NAME", saya menerima kesalahan sintaks yang saya sebutkan di atas. Saya telah menambahkan di ;antara ]itu. Saya juga pindah thenke baris berikutnya tanpa resolusi.

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

     if [ -r "$NAME" -af "$NAME" ] then
          wc -c "$NAME"
     fi
done

9
Setiap kali Anda memiliki kesalahan sintaksis shell, langkah pertama yang baik adalah memotong dan menempelkan kode Anda ke shellcheck.net dan memperbaiki kesalahan yang diidentifikasi. Jika Anda kesulitan memahami pesannya, datanglah ke sini dan tanyakan.
John1024

2
Apa yang -afseharusnya dilakukan?
ilkkachu

Terima kasih untuk situs itu @ John1024 itu yang paling berguna, saya telah menandainya untuk referensi di masa mendatang.
Christina A Guzman

1
@ChristinaAGuzman Dalam kasus seperti -aitu berlebihan karena kondisinya sudah termasuk di dalamnya -f. --- Bagaimanapun beberapa kondisi di dalam [ ](perintah ini juga tersedia sebagai test) harus digabungkan menggunakan operator logis seperti -a(dan) atau -o(atau) tetapi seperti yang disarankan dalam balasan di bawah ini, lebih baik menggunakan beberapa [ ]( test) perintah dan bergabung mereka menggunakan operator shell seperti &&atau ||.
pabouk

2
Christina, seperti yang ditunjukkan @ John1024, shellcheck.net menunjukkan dengan sangat jelas beberapa sintaks atau bahkan kesalahan yang lebih dalam (seperti serat untuk kode C). Saya juga merekomendasikan yang harus dibaca: mywiki.wooledge.org/BashPitfalls (baca setidaknya sekali!) Dan mywiki.wooledge.org/BashFAQ dan mywiki.wooledge.org/BashGuide juga baik untuk dibaca.
Olivier Dulac

Jawaban:


46

Kata kunci seperti if, then, else, fi, for, casedan sebagainya perlu berada di tempat di mana shell mengharapkan nama perintah. Kalau tidak, mereka diperlakukan sebagai kata-kata biasa. Sebagai contoh,

echo if

hanya mencetak if, itu tidak memulai instruksi bersyarat.

Dengan demikian, sejalan

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

kata tersebut thenadalah argumen dari perintah [(yang akan dikeluhkan jika dijalankan). Shell terus mencari then, dan menemukan fiposisi perintah. Karena ada ifyang masih mencari then, maka fitidak terduga, ada kesalahan sintaksis.

Anda harus meletakkan terminator perintah sebelum itu thensehingga dikenali sebagai kata kunci. Terminator perintah yang paling umum adalah jeda baris, tetapi sebelumnya then, sudah umum untuk menggunakan titik koma (yang memiliki arti yang sama persis dengan jeda baris).

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

atau

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

Setelah Anda memperbaikinya Anda akan mendapatkan kesalahan lain dari perintah [karena tidak mengerti -af. Anda mungkin dimaksudkan

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

Meskipun perintah tes terlihat seperti opsi, Anda tidak dapat menggabungkannya seperti ini. Mereka adalah operator dari [perintah dan mereka perlu masing-masing menjadi kata yang terpisah (seperti yang dilakukan [dan ]).

Ngomong-ngomong, meski [ -r "$NAME" -a -f "$NAME" ]bekerja, saya sarankan menulis juga

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

atau

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

Yang terbaik adalah menjaga [ … ]kondisional tetap sederhana karena [perintah tidak dapat membedakan operator dari operan dengan mudah. Jika $NAMEterlihat seperti operator dan muncul dalam posisi di mana operator itu valid, itu bisa diurai sebagai operator. Ini tidak akan terjadi dalam kasus-kasus sederhana yang terlihat dalam jawaban ini, tetapi kasus-kasus yang lebih kompleks dapat berisiko. Menulis ini dengan panggilan terpisah ke[ dan menggunakan operator logis shell menghindari masalah ini.

Sintaks kedua menggunakan [[ … ]]konstruksi kondisional yang ada di bash (dan ksh dan zsh, tetapi tidak sh polos). Membangun ini sintaks khusus, sedangkan [parsing seperti perintah lain, sehingga Anda dapat menggunakan hal-hal seperti &&di dalam dan Anda tidak perlu variabel kutipan kecuali dalam argumen untuk beberapa operator tali ( =, ==, !=, =~) (lihat Kapan double-mengutip diperlukan ? untuk perincian).


Perhatikan bahwa if [[ 1 ]] then [[ 2 ]] fibekerja di ksh, pdksh dan zsh. if(:)then(:)fibekerja di semua kerang.
Stéphane Chazelas

12

Lihat apa yang berubah sebagai berikut

jika [-r "$ NAME" -a -f "$ NAME"] ; kemudian
# ^^^^^ ^
     wc -c "$ NAME"
fi

Jika Anda ingin menghapus semua perintah di blok if, Anda setidaknya perlu menambahkan titik dua di dalamnya, seperti

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

atau versi satu baris

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


2

Orang lain sudah menunjukkan, tetapi jika Anda mencari referensi resmi maka RTM

jika daftar; kemudian daftar; [daftar elif; kemudian daftar; ] ... [daftar lain;] fi

Daftar if dijalankan. Jika status keluarnya nol, daftar itu dijalankan. Jika tidak, setiap daftar elif dieksekusi pada gilirannya, dan jika status keluarnya nol, maka daftar yang sesuai dieksekusi dan perintah selesai. Kalau tidak, daftar yang lain dijalankan, jika ada. Status keluar adalah status keluar dari perintah terakhir yang dijalankan, atau nol jika tidak ada kondisi yang diuji benar.

Anda melewatkan ;

Dan sintaks untuk listdijelaskan dalamman test

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.