Lỗi cú pháp Bash khi khác người khác theo sau một mệnh đề trống sau đó


36

Tại sao tập lệnh sau không được thực thi, nhưng đưa ra lỗi cú pháp là else:

LOGS3_DIR=~/logs
if [ -d "$LOGS3_DIR" ]; then
 cd
 cd "$LOGS3_DIR"
 echo "$LOGS3_DIR"
 for filename in `find "." -mtime 1 -type f`
  do
  if lsof "$filename" > /dev/null
  then
    # file is open
  else
    echo "deleting $filename"
    rm "$filename"
  fi
 done
fi

Câu trả lời:


23

Không sử dụng thay thế lệnh trên đầu ra củafind . Ở đây, mọi thứ có thể được thực hiện với find:

find . -mtime 1 -type f ! -exec lsof -t {} \; -exec rm -f {} \; > /dev/null

Với một vài findtriển khai (bao gồm FreeBSD findcó nguồn gốc từ GNU và GNU find), bạn có thể sử dụng -deletethay vì -exec rm....

Lý do bạn gặp lỗi là vì không có lệnh giữa thenelsemột số shell (bắt đầu với shell Bourne nơi cú pháp đó xuất phát) yêu cầu ít nhất một (và một nhận xét không phải là lệnh). Lưu ý rằng nó hoàn toàn tùy ý và không có lý do tại sao những chiếc vỏ đó sẽ làm điều đó. yashzshkhông có giới hạn đó ( if false; then else echo x; fivà thậm chí if false; then else fihoạt động tốt với họ).

Như những người khác đã nói, bạn có thể sử dụng lệnh noop như :(hoặc for nothing in; do nothing; done) hoặc đảo ngược logic bằng !từ khóa (có sẵn trong shell POSIX, nhưng không phải là shell Bourne (bạn sẽ thấy rằng sử dụng :cho điều đó là phổ biến trong shell đó)). mkshvà tình yashcờ hỗ trợ if false; then () else echo x; fi(tôi sẽ không dựa vào nó vì điều đó có thể thay đổi trong các phiên bản trong tương lai).

Một cách tiếp cận khác là:

lsof... || {
  cmd1
  cmd2
}

mặc dù một sự khác biệt là trạng thái thoát tổng thể sẽ là tình trạng lsofnếu lsofthất bại.


17
Mặc dù đây là cách tốt hơn nhiều để thực hiện những gì Người dùng @Novice đang cố gắng, nhưng nó hoàn toàn không trả lời câu hỏi.
SeeJayBee

Mặc dù -execthường hữu ích xargs, đôi khi, một vòng lặp shell là cần thiết. Trong trường hợp đó, một while read namevòng lặp là tùy chọn ưa thích (trong bash với GNU find, bạn có thể sử dụng tùy chọn -0 cho cả hai; chắc chắn bạn phải từ bỏ dòng mới).
Jan Hudec

@JanHudec, Có nhiều cách. -print0-exec printf '%s\0' {} +(nhưng có thể bạn không thể đối phó với đầu ra đó trừ khi bạn muốn xem xét perl) và với find .//.và một số xử lý hậu kỳ, bạn có thể thoát khỏi các dòng mới cho xargs. Lưu ý rằng nó không phải là một while read, nó while IFS= read -r.
Stéphane Chazelas

@Chris, tôi đã thêm câu trả lời cho câu hỏi thực tế kể từ khi câu trả lời cuối cùng được chấp nhận.
Stéphane Chazelas

91

Có vẻ như bạn muốn thực hiện no-op nếu tệp đang mở vì vậy bạn nên thêm a :, đó là lệnh null trong bash:

if lsof "$filename" > /dev/null; then
  # file is open
  :
else
  printf 'deleting %s\n' "$filename"
  rm -- "$filename"
fi

Nếu bạn không sử dụng :, bashkhông thể phân tích mã của bạn và sẽ hiển thị lỗi như thế nào bash: syntax error near unexpected token 'else'.


không bao giờ mới :và đó là lệnh đầu tiên được liệt kê trong bash-buildin.
bolov

26

Một cách khác: đảo ngược logic của bạn.

if ! lsof "$filename" >/dev/null;then
    echo "deleting $filename"
    rm "$filename"
fi

17

TL; DR

Không có câu trả lời nào khác thực sự giải quyết câu hỏi ban đầu của bạn về lý do tại sao lệnh đưa ra lỗi cú pháp. Điều này được gây ra bởi một lệnh bị thiếu giữa lúc đókhác .

Một lệnh mất tích

Mã ban đầu của bạn trông như thế này:

if lsof "$filename" > /dev/null
then
  # file is open
else
  echo "deleting $filename"
  rm "$filename"
fi

Vấn đề là bạn có một bình luận giữa lúc đó và lúc khác , nhưng bình luận không được coi là một lệnh. Nói tóm lại, bạn có thể viết lại vấn đề bạn gặp phải (nói theo cấu trúc) như sau:

$ if true; then else echo; fi
bash: syntax error near unexpected token `else'

Sửa lỗi Cú pháp của bạn với Bản dựng Bourne

Bạn có thể khắc phục sự cố này bằng cách đặt các lệnh thực tế trước các lệnh khác , nhưng tự nó sẽ không nhận xét. Phần if-then không thể để trống; nếu bạn muốn giữ chỗ, bạn có thể sử dụng nội dung tích hợp . Ví dụ:

$ if true; then :; else echo; fi

Đơn giản chỉ cần đặt :vào phần giữa sau đókhác sẽ sửa chữa các lỗi cú pháp bạn đang gặp phải.


1
Câu trả lời của Gnouc, cũng là câu trả lời được đánh giá cao nhất, đã nhấn mạnh câu hỏi ban đầu.
jlliagre

Chỉ trả lời để giải quyết lỗi cú pháp. FWIW, bạn có thể tái tạo một lỗi tương tự với dấu chấm phẩy duy nhất ở đầu dòng. Điều này sẽ cho một gợi ý mạnh mẽ. $ ; -bash: syntax error near unexpected token ';'
Matthew Hannigan
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.