"else"가 빈 "then"절 뒤에 올 때 Bash 구문 오류


35

다음 스크립트가 실행되지 않지만 구문 오류가 발생하는 이유는 다음과 같습니다 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

답변:


23

의 출력에서 ​​명령 대체를 사용하지 마십시오find . 여기서 모든 작업을 수행 할 수 있습니다 find.

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

몇 가지 find구현 (FreeBSD find및 GNU에서 제공)을 포함 find하여 -delete대신에 사용할 수 있습니다 -exec rm....

오류를 얻고있는 이유는이 사이에 명령을 없습니다 것입니다 thenelse및 (그 구문에서 오는 Bourne 쉘로 시작하는) 일부 포탄 적어도 하나가 필요합니다 (그리고 주석이 명령하지 않습니다). 그것은 완전히 임의적이며 그러한 쉘이 그렇게 할 이유가 없습니다. yash그리고 zsh그 한계가 없습니다 ( if false; then else echo x; fi그리고 if false; then else fi그들과 잘 작동합니다).

다른 사람들이 말했듯이 :(또는 for nothing in; do nothing; done) 와 같은 noop 명령을 사용 하거나 !키워드를 사용 하여 논리를 되돌릴 수 있습니다 (POSIX 셸에서는 사용 가능하지만 Bourne 셸에서는 사용 가능하지 않습니다 (이 셸 :에서 일반적으로 사용됨)). mksh그리고 yash지원이 발생합니다 if false; then () else echo x; fi(향후 버전에서는 변경 될 수 있으므로 의존하지 않습니다).

다른 접근 방식은 다음과 같습니다.

lsof... || {
  cmd1
  cmd2
}

한 가지 차이점은 전체 종료 상태이며 이는 실패 하는 lsof경우 lsof입니다.


17
이것은 @ 초보자 사용자가 시도하는 것을 수행하는 훨씬 더 좋은 방법이지만 질문에 전혀 대답하지는 않습니다.
SeeJayBee

-exec종종 유용 하지만 xargs때로는 쉘 루프가 필요합니다. 어떤 경우에는 while read name루프가 선호되는 옵션입니다 (GNU find의 bash에서는 둘 다 -0 옵션을 사용할 수 있습니다.
Jan Hudec

@ JanHudec, 이식 가능한 방법이 있습니다. -print0이다 -exec printf '%s\0' {} +(그러나 이식 당신은 당신이 고려할 경우를 제외하고 그 출력을 처리 할 수없는 perl), 및과 find .//.일부 사후 처리, 당신은에 대한 줄 바꿈을 피할 수 있습니다 xargs. 이 아닌 while read, while IFS= read -r입니다.
Stéphane Chazelas

@Chris, 답변이 끝났으므로 실제 질문에 대한 답변을 추가했습니다.
Stéphane Chazelas

90

파일이 열려 있으면 아무 작업도 수행하지 않으려 는 경우 다음 :과 같이 null 명령 인을 추가해야합니다 bash.

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

사용하지 않는 경우 :, bash당신은 코드를 구문 분석 할 수 없습니다와 같은 오류가 표시됩니다 bash: syntax error near unexpected token 'else'.


결코 새로운 :것이 아니며 bash-builtins에 나열된 첫 번째 명령입니다.
bolov

26

다른 대안 : 논리를 바꾸십시오.

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

17

TL; DR

다른 답변은 실제로 명령이 구문 오류를 발생시키는 이유에 대한 원래의 질문을 다루지 않습니다. 이것은 thenelse 사이의 명령이 없기 때문에 발생 합니다 .

빠진 명령

원래 코드는 다음과 같습니다.

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

문제는 thenelse 사이 에 주석이 있지만 주석은 명령으로 취급되지 않는다는 것입니다. 간단히 말해 다음과 같이 (구조적으로 말하면) 문제를 다시 작성할 수 있습니다.

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

본 내장으로 구문 수정

실제 명령을 else 앞에 배치하여이 문제를 해결할 수 있지만 주석 자체는 그렇지 않습니다. 경우 - 다음 섹션은 비워 둘 수 없습니다; 자리 표시자를 원하면 콜론 builtin을 사용할 수 있습니다 . 예를 들면 다음과 같습니다.

$ if true; then :; else echo; fi

간단하게 배치 :사이의 섹션으로 다음다른 발생한 구문 오류를 수정합니다.


1
가장 유력한 답변 인 Gnouc의 답변은 이미 원래의 질문을 다루고 있습니다.
jlliagre 2016 년

구문 오류를 해결하기 위해서만 대답하십시오. FWIW에서는 줄의 시작 부분에 단독 세미콜론으로 유사한 오류를 재현 할 수 있습니다. 이것은 강력한 힌트를 줄 것입니다. $ ; -bash: syntax error near unexpected token ';'
Matthew Hannigan
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.