Beklenmedik belirteç `fi` yakınında sözdizimi hatası


17

Cevabı mutlaka istemiyorum ama birisi beni bazı literatür veya örneklere yönlendirebilirse. Bunu anlamak istiyorum.

Komut dosyasını çalıştırdığımda bir hata alıyorum:

Beklenmeyen belirtecin yanında sözdizimi hatası fi

ifBeyanlarımı açıklamalarımı yaparak ve isimleri görüntüleyenleri ifekleyerek sorunumun ifademde olduğunu echo "$NAME"belirttim /etc/.

Ben değişiklik yaptığınızda, kaldırmak #gelen ifve five eklemek #için wc -c "$NAME"ben yukarıda listelenen sözdizimi hatası alırsınız. O zaman ;arasına ekledim ]. Ayrıca thenherhangi bir çözüm olmadan bir sonraki satıra geçtim .

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

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

9
Bir kabuk sözdizimi hatası olduğunda, kodunuzu shellcheck.net'e yapıştırıp tanımladığı hataları düzeltmek için iyi bir ilk adımdır . Mesajlarını anlamakta zorluk çekiyorsanız, buraya gelin ve sorun.
John1024

2
Bu ne -afyapmalı?
ilkkachu

Bu site için teşekkür ederim @ John1024 en yararlı oldu, ben ileride başvurmak için yer imi var.
Christina A Guzman

1
@ChristinaAGuzman Böyle bir durumda -a, durum zaten dahil edildiği için gereksizdir -f. --- Her neyse [ ](bu komut da test) içinde birden fazla koşulun -a(ve) veya -o(veya) gibi mantıksal işleçler kullanılarak birleştirilmesi gerekir, ancak aşağıdaki yanıtta önerildiği gibi, çoklu [ ]( test) komutları kullanmak ve katılmak daha iyidir &&veya gibi kabuk işleçlerini kullanarak ||.
pabouk

2
@ John1024'te belirtildiği gibi Christina, shellcheck.net çok açık bir şekilde bazı sözdizimi veya daha derin hatalar gösteriyor ( tüyler C kodu için olduğu gibi). Ayrıca şunu da okumalısınız: mywiki.wooledge.org/BashPitfalls (en az bir kez okuyun!) Ve mywiki.wooledge.org/BashFAQ ve mywiki.wooledge.org/BashGuide da okumak iyi.
Olivier Dulac

Yanıtlar:


46

Anahtar kelimeler gibi if, then, else, fi, for, caseve bu yüzden ihtiyaca kabuk komut adını beklediği bir yerde olması. Aksi takdirde sıradan kelimeler olarak muamele görürler. Örneğin,

echo if

sadece yazdırır if, koşullu bir talimat başlatmaz.

Böylece,

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

kelime then, komutun bir argümanıdır ( [çalıştırılması gerekip gerekmediğinden şikayet eder). Kabuk, karakterini aramaya devam eder thenve bir fikomut konumunda bulur . Bir olmadığına göre ifhala onun aradığını olduğunu then, fibeklenmedik bir sözdizimi hatası var.

thenAnahtar kelime olarak tanınabilmesi için önce bir komut sonlandırıcısı koymanız gerekir . En yaygın komut sonlandırıcısı satır kesmesidir, ancak daha önce thennoktalı virgül (satır kesmesi ile tamamen aynı anlama gelen) kullanmak yaygındır.

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

veya

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

Bunu düzelttikten sonra, komuttan başka bir hata alırsınız [çünkü anlamıyor -af. Muhtemelen demek istedin

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

Test komutları seçenek gibi görünse de, bunları böyle paketleyemezsiniz. Onlar [komutun operatörleridir ve her birinin ayrı bir kelime olması gerekir ( [ve olduğu gibi ]).

Bu arada, her ne kadar [ -r "$NAME" -a -f "$NAME" ]çalışıyor olsa da , ben de yazmayı öneririm

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

veya

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

[ … ]Koşulları basit tutmak en iyisidir çünkü [komut operatörleri işlenenden kolayca ayırt edemez. Bir $NAMEoperatöre benziyorsa ve operatörün geçerli olduğu bir konumda görünüyorsa, operatör olarak ayrıştırılabilir. Bu, bu cevapta görülen basit vakalarda gerçekleşmeyecek, ancak daha karmaşık vakalar riskli olabilir. Bunu ayrı çağrılarla yazmak [ve kabuğun mantıksal işleçlerini kullanmak bu sorunu önler.

İkinci sözdizimi [[ … ]]bash (ve ksh ve zsh, ancak düz sh değil) içinde bulunan koşullu yapıyı kullanır . Bu yapı özel bir sözdizimi, oysa edilir [böylece gibi şeyler kullanabilirsiniz, herhangi başka bir komut gibi ayrıştırılır &&iç ve bazı dize operatörlerine argümanları hariç alıntı değişkenleri gerekmez ( =, ==, !=, =~) (bkz çift alıntı gerekli olduğunda ? ) detaylar için.


if [[ 1 ]] then [[ 2 ]] fiKsh, pdksh ve zsh olarak çalıştığını unutmayın . if(:)then(:)fitüm kabuklarında çalışır.
Stéphane Chazelas

12

Nelerin değiştiğini aşağıdaki gibi görün

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

İf block içindeki tüm komutları kaldırmak istiyorsanız, en azından içine iki nokta üst üste eklemeniz gerekir.

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

veya bir satır sürümü

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


2

Diğerleri zaten işaret etti, ancak resmi referans arıyorsanız RTM

eğer liste; sonra sıralayın; [elif listesi; sonra sıralayın; ] ... [başka liste;] fi

İf listesi yürütülür. Çıkış durumu sıfırsa, o zaman liste yürütülür. Aksi takdirde, her elif listesi sırayla yürütülür ve çıkış durumu sıfırsa, karşılık gelen liste yürütülür ve komut tamamlanır. Aksi takdirde, varsa diğer liste yürütülür. Çıkış durumu, yürütülen son komutun çıkış durumudur veya hiçbir koşul test edilmediğinde sıfırdır.

Eksik ;

Ve sözdizimi listaçıklanmaktadırman test

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.