구문 오류로 인해 bash가 스크립트 실행을 중단시키는 방법은 무엇입니까?


15

안전 측면에서 bash는 구문 오류가 발생하면 bash가 스크립트 실행을 중단하고 싶습니다.

놀랍게도 나는 이것을 달성 할 수 없습니다. ( set -e충분하지 않습니다.) 예 :

#!/bin/bash

# Do exit on any error:
set -e

readonly a=(1 2)

# A syntax error is here:

if (( "${a[#]}" == 2 )); then
    echo ok
else
    echo not ok
fi

echo status $?

echo 'Bad: has not aborted execution on syntax error!'

결과 (bash-3.2.39 또는 bash-3.2.51) :

$ ./sh-on-syntax-err
./sh-on-syntax-err: line 10: #: syntax error: operand expected (error token is "#")
status 1
Bad: has not aborted execution on syntax error!
$ 

우리는 $?구문 오류를 잡기 위해 모든 명령문을 검사 할 수 없습니다 .

(나는 합리적인 프로그래밍 언어에서 그러한 안전한 행동을 기대했다. 아마도 이것은 개발자를 강타하는 버그 / 소위로보고되어야한다)

더 많은 실험

if 차이가 없습니다.

제거 중 if:

#!/bin/bash

set -e # exit on any error
readonly a=(1 2)
# A syntax error is here:
(( "${a[#]}" == 2 ))
echo status $?
echo 'Bad: has not aborted execution on syntax error!'

결과:

$ ./sh-on-syntax-err 
./sh-on-syntax-err: line 6: #: syntax error: operand expected (error token is "#")
status 1
Bad: has not aborted execution on syntax error!
$ 

아마도 이것은 http://mywiki.wooledge.org/BashFAQ/105의 연습 2와 관련이 있으며 관련 이 있습니다 (( )). 그러나 구문 오류가 계속 발생하면 여전히 불합리합니다.

아니요, (( ))차이가 없습니다!

산술 테스트 없이도 잘못 작동합니다! 간단하고 기본적인 스크립트 :

#!/bin/bash

set -e # exit on any error
readonly a=(1 2)
# A syntax error is here:
echo "${a[#]}"
echo status $?
echo 'Bad: has not aborted execution on syntax error!'

결과:

$ ./sh-on-syntax-err 
./sh-on-syntax-err: line 6: #: syntax error: operand expected (error token is "#")
status 1
Bad: has not aborted execution on syntax error!
$ 

set -e구문 오류가 if명령문 에 있기 때문에 충분하지 않습니다 . 다른 곳에서는 스크립트를 중단해야합니다.
jordanm

@jordanm Ok, 이것이 set -e효과가없는 이유 를 설명 할 수 있습니다 . 그러나 내 질문은 여전히 ​​타당합니다. 구문 오류를 중단 할 수 있습니까?
imz-Ivan Zakharyaschev

@jordanm "if"가 제거되었습니다. 차이가 없습니다 (내 질문이 업데이트되었습니다).
imz-Ivan Zakharyaschev

답변:


9

전체를 함수로 감싸는 것은 트릭을 수행하는 것처럼 보입니다.

#!/bin/bash -e

main () {
readonly a=(1 2)
    # A syntax error is here:
    if (( "${a[#]}" == 2 )); then
        echo ok
    else
        echo not ok
    fi
    echo status $?
    echo 'Bad: has not aborted execution on syntax error!'
}

main "$@"

결과:

$ ./sh-on-syntax-err 
$ ./sh-on-syntax-err line 6: #: syntax error: operand expected (error token is "#")
$ 

왜 실마리는 없지만 다른 누군가가 설명 할 수 있습니까?


2
이제 함수 정의가 구문 분석되고 평가되어 실패합니다.
tripleee

좋은 해결책! BTW,이 경우 전체 프로그램을 중단하지 않습니다. echo 'Bad2: has not aborted the execution after bad main!'예제에 마지막으로 추가 했으며 출력은 $ LC_ALL = C ./sh-on-syntax-err ./sh-on-syntax-err : line 6 : # : syntax error : operand expected ( 오류 토큰은 "#"입니다. Bad2 : 잘못된 메인 후에 실행이 중단되지 않았습니다! $
imz-Ivan Zakharyaschev

그러나 우리는 단순히 행을 추가해서는 안되며 모든 것을 함수 안에 넣어야합니다.
imz-Ivan Zakharyaschev

@tripleee 예, 함수 구문 분석이 실패한 것처럼 보이므로 완전하지는 않지만 실제로이 경우 전체 프로그램이 중단되지 않습니다 (따라서 종료시 오류의 영향은 아닙니다).
imz-Ivan Zakharyaschev

6

의 진정한 의미에 대해 오도했을 것입니다 set -e. help set쇼 의 출력을주의 깊게 읽습니다 .

-e  Exit immediately if a command exits with a non-zero status.

그래서 -e의 종료 상태에 관한 명령이 아닌 스크립트 구문 오류에 대한 비 - 제로, 인.

일반적으로 set -e모든 오류 (예 : 명령에서 0이 아닌 모든 반환 값)는 스크립트에서 스마트하게 처리해야하므로 강력한 스크립트를 생각해야합니다. 공간 또는 하이픈으로 시작).

구문 오류 유형에 따라 스크립트가 전혀 실행되지 않을 수도 있습니다. 나는 bash에서 어떤 클래스의 구문 오류 (만 분류 할 수있는 경우)가 스크립트를 즉시 중단시킬 수 있는지 정확하게 알 수 없습니다. 어쩌면 일부 배쉬 전문가들이 참여하여 모든 것을 명확히 할 것입니다.

나는 그 set -e진술을 명확히하기를 희망한다 !

당신의 소원에 관하여 :

나는 현명한 프로그래밍 언어로부터 그러한 안전한 행동을 기대했다.

대답은 확실히 아니오입니다! set -e실제로 관찰 한 내용 ( 예상대로 응답하지 않음)이 실제로 잘 기록되어 있습니다.


나는 그러한 기능이 없다는 것이 문제라는 것을 의미했다. 나는 초점을 맞추고 싶지 않았습니다. set -e그것은 나의 목표에 조금 가깝기 때문에 여기에서 언급되고 사용됩니다. 내 질문은에 관한 것이 아니라 set -esytax 오류를 중단시킬 수 없다면 bash의 안전에 관한 것입니다. 구문 오류가 항상 중단되도록하는 방법을 찾고 있습니다.
imz-Ivan Zakharyaschev

4

다음과 같은 것을 넣어 스크립트 자체를 확인할 수 있습니다.

bash -n "$0"

스크립트의 맨 위 근처- set -e중요한 코드의 앞뒤 .

나는 이것이 매우 강하게 느껴지지 않는다고 말해야하지만 그것이 당신에게 효과적이라면 아마도 받아 들일 수 있습니다.


우수한! 또는,없이 set -e: bash -n "$0" || exit
Daniel S

0

먼저 (( ))in bash는 산술 계산으로 사용되며 if ...에는 사용하지 않습니다 [].

둘째, ${a[#]}이상하고 그것이 오류를 일으키는 이유입니다 ... #배열 의미가 없습니다.

난 당신이 수행 할 작업 모르겠지만, 당신이 원하는 그래서, 당신은 필드의 수를 알고 싶은 가정 ${#a[*]}대신

마지막으로 정수를 비교할 때 (문자열에 사용) -eq이상을 권장 ==합니다. 는 ==또한 작동하지만 -eq권장합니다.

그래서 당신은 원합니다 :

if [ ${#a[*]} -eq 2 ]; then 

4
그건 사실이 아니야. ((키워드와 키워드를 함께 사용하는 것이 일반적 if입니다. 예를 들면 다음과 같습니다 if (( 5 * $b > 53 )). 나이가 껍질 휴대 성을 목표로하지 않는 한, [[이다 일반적으로 바람직 이상 [.

2
예, @Evan에 동의 - [[((경량 테스트를 함께 사용하도록 특별히 설계되었습니다 등 "만일"-는 달리 [, 그들은 조건을 평가하는 서브 프로세스를 생성하지 않습니다.
imz-Ivan Zakharyaschev

1
[bash 내장입니다. 오래된 쉘은 자체 프로그램이기를 기대합니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.