Lỗi cú pháp gần mã thông báo bất ngờ `fi`


17

Tôi không nhất thiết muốn câu trả lời nhưng nếu ai đó có thể chỉ cho tôi một số tài liệu hoặc ví dụ. Tôi muốn tìm ra nó.

Khi tôi chạy tập lệnh, tôi nhận được một lỗi:

Lỗi cú pháp gần mã thông báo bất ngờ fi

Tôi đã suy luận rằng vấn đề của tôi nằm trong iftuyên bố của mình bằng cách đưa ra ifnhận xét của mình và thêm echo "$NAME"phần hiển thị tên trong /etc/.

Khi tôi thực hiện thay đổi, loại bỏ các #từ iffivà thêm #vào wc -c "$NAME", tôi nhận được lỗi cú pháp tôi liệt kê ở trên. Tôi đã thêm vào ;giữa ]sau đó. Tôi cũng đã chuyển thensang dòng tiếp theo mà không có độ phân giải.

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

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

9
Bất cứ khi nào bạn gặp lỗi cú pháp shell, bước đầu tiên tốt là cắt và dán mã của bạn vào shellcheck.net và sửa các lỗi mà nó xác định. Nếu bạn gặp khó khăn trong việc hiểu các thông điệp của nó, thì hãy đến đây và hỏi.
John1024

2
Những gì -afphải làm?
ilkkachu

Cảm ơn bạn cho trang web đó @ John1024 nó hữu ích nhất, tôi đã đánh dấu nó để tham khảo trong tương lai.
Christina A Guzman

1
@ChristinaAGuzman Trong trường hợp như vậy -alà dư thừa vì điều kiện đã được bao gồm trong -f. --- Dù sao, nhiều điều kiện trong [ ](lệnh này cũng có sẵn vì test) phải được tham gia bằng cách sử dụng các toán tử logic như -a(và) hoặc -o(hoặc) nhưng như đã đề xuất trong câu trả lời bên dưới, tốt hơn là sử dụng nhiều lệnh [ ]( test) và tham gia họ sử dụng các toán tử shell như &&hoặc ||.
pabouk

2
Christina, như đã chỉ ra @ John1024, shellcheck.net cho thấy rất rõ một số cú pháp hoặc thậm chí sai lầm sâu hơn (như lint làm cho mã C). Tôi cũng khuyên bạn nên đọc: mywiki.wooledge.org/BashPit thác (đọc ít nhất một lần!) Và mywiki.wooledge.org/BashFAQmywiki.wooledge.org/BashGuide cũng rất tốt để đọc.
Olivier Dulac

Câu trả lời:


46

Các từ khóa như if, then, else, fi, for, casevà vân vân cần phải ở một nơi mà vỏ hy vọng một tên lệnh. Nếu không, chúng được coi là những từ thông thường. Ví dụ,

echo if

chỉ in if, nó không bắt đầu một hướng dẫn có điều kiện.

Như vậy, trong dòng

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

từ thennày là một đối số của lệnh [(mà nó sẽ phàn nàn nếu nó phải chạy). Shell tiếp tục tìm kiếm thenvà tìm thấy một fivị trí chỉ huy. Vì có một ifthứ vẫn đang tìm kiếm nó then, fithật bất ngờ, có lỗi cú pháp.

Bạn cần đặt một bộ kết thúc lệnh trước thenđể nó được công nhận là một từ khóa. Dấu kết thúc lệnh phổ biến nhất là ngắt dòng, nhưng trước đây then, thông thường sử dụng dấu chấm phẩy (có ý nghĩa chính xác giống như ngắt dòng).

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

hoặc là

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

Khi bạn sửa lỗi, bạn sẽ nhận được một lỗi khác từ lệnh [vì nó không hiểu -af. Bạn có lẽ có nghĩa là

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

Mặc dù các lệnh kiểm tra trông giống như các tùy chọn, bạn không thể gói chúng như thế này. Họ là những người vận hành [lệnh và mỗi người cần phải là một từ riêng biệt (cũng như []).

Nhân tiện, mặc dù [ -r "$NAME" -a -f "$NAME" ]hoạt động, tôi khuyên bạn nên viết

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

hoặc là

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

Tốt nhất là giữ các [ … ]điều kiện đơn giản vì [lệnh không thể phân biệt toán tử với toán hạng một cách dễ dàng. Nếu $NAMEtrông giống như một toán tử và xuất hiện ở vị trí mà toán tử hợp lệ, nó có thể được phân tích cú pháp như một toán tử. Điều này sẽ không xảy ra trong các trường hợp đơn giản được thấy trong câu trả lời này, nhưng các trường hợp phức tạp hơn có thể có rủi ro. Viết điều này bằng các lệnh gọi riêng [và sử dụng các toán tử logic của shell sẽ tránh được vấn đề này.

Cú pháp thứ hai sử dụng [[ … ]]cấu trúc có điều kiện tồn tại trong bash (và ksh và zsh, nhưng không phải là sh đơn giản). Cấu trúc này được cú pháp đặc biệt, trong khi [được phân tách giống như bất kỳ lệnh khác, do đó bạn có thể sử dụng những thứ như &&bên trong và bạn không cần phải biến quote trừ đối số cho một số nhà khai thác chuỗi ( =, ==, !=, =~) (xem Khi nào đúp trích dẫn cần thiết ? để biết chi tiết).


Lưu ý rằng if [[ 1 ]] then [[ 2 ]] fihoạt động trong ksh, pdksh và zsh. if(:)then(:)fihoạt động trong tất cả các vỏ.
Stéphane Chazelas

12

Xem những gì đã thay đổi như sau

if [-r "$ NAME" -a -f "$ NAME"] ; sau đó
# ^ ^ ^ ^ ^ ^
     wc -c "$ TÊN"
fi

Nếu bạn muốn xóa tất cả các lệnh trong khối if, ít nhất bạn cần thêm dấu hai chấm trong đó, như

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

hoặc một phiên bản dòng

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


2

Những người khác đã chỉ ra, nhưng nếu bạn đang tìm kiếm tài liệu tham khảo chính thức thì RTM

nếu danh sách; sau đó liệt kê; [danh sách elif; sau đó liệt kê; ] ... [danh sách khác;] fi

Danh sách if được thực thi. Nếu trạng thái thoát của nó bằng 0, danh sách thì được thực thi. Mặt khác, mỗi danh sách elif được thực thi lần lượt và nếu trạng thái thoát của nó bằng 0, thì danh sách sau đó tương ứng được thực thi và lệnh hoàn thành. Mặt khác, danh sách khác được thực thi, nếu có. Trạng thái thoát là trạng thái thoát của lệnh cuối cùng được thực thi hoặc bằng 0 nếu không có điều kiện nào được kiểm tra đúng.

Bạn đang thiếu ;

Và cú pháp listđược mô tả trongman test

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.