[linux] bash 스크립트에서 set -e는 무엇을 의미합니까?

패키지가 데비안 아카이브 (.deb) 파일에서 압축 해제되기 전에 스크립트가 실행하는 이 preinst 파일 의 내용을 연구하고 있습니다 .

스크립트에는 다음 코드가 있습니다.

#!/bin/bash
set -e
# Automatically added by dh_installinit
if [ "$1" = install ]; then
   if [ -d /usr/share/MyApplicationName ]; then
     echo "MyApplicationName is just installed"
     return 1
   fi
   rm -Rf $HOME/.config/nautilus-actions/nautilus-actions.conf
   rm -Rf $HOME/.local/share/file-manager/actions/*
fi
# End automatically added section

첫 번째 질문은 다음과 같습니다.

set -e

스크립트의 나머지 부분은 매우 간단하다고 생각합니다. 데비안 / 우분투 패키지 관리자가 설치 작업을 실행하고 있는지 확인합니다. 있는 경우 내 응용 프로그램이 시스템에 설치되었는지 확인합니다. 있는 경우 스크립트는 “MyApplicationName이 설치되었습니다”라는 메시지를 인쇄 하고 종료됩니다 ( return 1“오류”로 끝나지 않습니까?).

사용자가 데비안 / 우분투 패키지 시스템에 패키지 설치를 요청하면 스크립트는 두 디렉토리도 삭제합니다.

이것이 맞습니까? 아니면 뭔가 빠졌습니까?



답변

보낸 사람 help set:

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

그러나 일부에서는 나쁜 습관으로 간주됩니다 (bash FAQ 및 irc freenode #bash FAQ 작성자). 다음을 사용하는 것이 좋습니다.

trap 'do_something' ERR

do_something오류 발생시 기능 을 실행 합니다.

http://mywiki.wooledge.org/BashFAQ/105 참조


답변

set -e명령 또는 파이프 라인에 오류가있는 경우 스크립트 실행을 중지합니다. 이는 스크립트의 오류를 무시하는 기본 쉘 동작과 반대입니다. help set이 내장 명령에 대한 설명서를 보려면 터미널을 입력 하십시오.


답변

bash에 따라 -Set Builtin manual, -e/ errexit가 설정되면 단일 간단한 명령 , 목록 또는 복합 명령 으로 구성된 파이프 라인이 있으면 쉘이 즉시 종료됩니다. 반환이 아닌 제로 상태입니다.

기본적으로 파이프 라인의 종료 상태는 파이프 라인에서 마지막 명령의 종료 상태입니다. pipefail옵션이 활성화되어 (기본적으로 비활성화되어 있음) .

그렇다면 파이프 라인의 마지막 (가장 오른쪽) 명령의 리턴 상태가 0이 아닌 상태로 종료되거나 모든 명령이 성공적으로 종료되면 0입니다.

종료시 무언가를 실행하려면 다음과 같이 정의하십시오 trap.

trap onexit EXIT

여기서 onexit같은 그 이하 간단한 인쇄되고, 출구에 뭔가를 할 수있는 함수입니다 스택 추적 :

onexit(){ while caller $((n++)); do :; done; }

비슷한 옵션 -E/가errtrace 있으며 대신 ERR을 잡을 수 있습니다.

trap onerr ERR

제로 상태 예 :

$ true; echo $?
0

0이 아닌 상태 예 :

$ false; echo $?
1

부정 상태 예 :

$ ! false; echo $?
0
$ false || true; echo $?
0

pipefail비활성화 된 상태에서 테스트 :

$ bash -c 'set +o pipefail -e; true | true | true; echo success'; echo $?
success
0
$ bash -c 'set +o pipefail -e; false | false | true; echo success'; echo $?
success
0
$ bash -c 'set +o pipefail -e; true | true | false; echo success'; echo $?
1

pipefail활성화 된 상태에서 테스트 :

$ bash -c 'set -o pipefail -e; true | false | true; echo success'; echo $?
1


답변

로 인해 중단 된 스크립트의 종료 상태가 무엇인지 파악하려고 시도하는 동안이 게시물을 찾았습니다 set -e. 대답은 나에게 명백하지 않았다. 따라서이 답변. 기본적으로 set -e명령 실행 (예 : 셸 스크립트)을 중단하고 실패한 명령의 종료 상태 코드 (예 : 외부 스크립트가 아닌 내부 스크립트)를 반환합니다. .

예를 들어, 쉘 스크립트가 있다고 가정하십시오 outer-test.sh.

#!/bin/sh
set -e
./inner-test.sh
exit 62;

코드 inner-test.sh는 다음과 같습니다.

#!/bin/sh
exit 26;

outer-script.sh명령 줄에서 실행하면 외부 스크립트가 내부 스크립트의 종료 코드로 종료됩니다.

$ ./outer-test.sh
$ echo $?
26


답변

그 의도는 문제의 스크립트가 빠르게 실패하는 것이라고 생각합니다.

직접 테스트하려면 set -ebash 프롬프트에서 입력하십시오 . 이제 실행 해보십시오 ls. 디렉토리 목록이 나타납니다. 이제을 입력하십시오 lsd. 이 명령은 인식되지 않고 오류 코드를 반환하므로 bash 프롬프트가 닫힙니다 (로 인해 set -e).

이제 ‘스크립트’의 맥락에서 이것을 이해하려면 다음 간단한 스크립트를 사용하십시오.

#!/bin/bash 
# set -e

lsd

ls

그대로 실행 ls하면 마지막 줄 에서 디렉토리 목록을 얻을 수 있습니다. 의 주석을 해제하고 set -e다시 실행하면 bash에서 오류가 발생하면 bash가 처리를 중지하므로 디렉토리 목록이 표시되지 않습니다 lsd.


답변

이것은 오래된 질문이지만 데비안 패키지 처리 스크립트에서 set -e일명 사용에 대해서는 여기에 답변이 없습니다 set -o errexit. 이 스크립트에서는 데비안 정책에 따라이 옵션을 반드시 사용해야합니다 . 의도는 처리되지 않은 오류 조건의 가능성을 피하기위한 것입니다.

이것이 실제로 의미하는 것은 실행하는 명령이 오류를 반환 할 수있는 조건을 이해하고 각 오류를 명시 적으로 처리해야한다는 것입니다.

일반적인 문제는 (예 : diff차이 grep가있을 때 오류를 반환 ) 및 (일치가 없으면 오류를 반환)입니다. 명시 적 처리로 오류를 피할 수 있습니다.

diff this that ||
  echo "$0: there was a difference" >&2
grep cat food ||
  echo "$0: no cat in the food" >&2

(메시지에 현재 스크립트 이름을 포함시키고 표준 출력 대신 표준 오류에 진단 메시지를 쓰는 방법에주의하십시오.)

명시 적 처리가 실제로 필요하거나 유용하지 않으면 명시 적으로 아무 것도 수행하지 마십시오.

diff this that || true
grep cat food || :

(셸의 :no-op 명령 사용은 약간 애매하지만 상당히 일반적입니다.)

반복해서 말하면

something || other

속기

if something; then
    : nothing
else
    other
fi

other, something실패 할 경우에만 실행해야한다고 명시 적으로 말하고 있습니다 . 긴 형식 if(와 같은 다른 쉘 흐름 제어 문은 while, until그것이 아니었다면),도와 쉘 스크립트 참으로 (오류를 처리 할 수있는 유효한 방법이다set -e 흐름 제어 문을 포함하지 않을 수 있습니다!)

또한 명시 적으로, 이와 같은 핸들러 set -e가 없으면 diff차이점을 grep찾거나 일치를 찾지 못하면 전체 스크립트가 즉시 오류와 함께 실패 합니다.

반면에 일부 명령은 원하는 경우 오류 종료 상태를 생성하지 않습니다. 일반적으로 문제가되는 명령은 find(종료 상태는 파일이 실제로 발견되었는지 여부를 반영하지 않음) 및 sed(종료 상태는 스크립트가 입력을 받았는지 또는 실제로 명령을 성공적으로 수행했는지 여부를 나타내지 않음)입니다. 일부 시나리오에서 간단한 가드는 출력이 없으면 소리를 지르는 명령으로 파이프하는 것입니다.

find things | grep .
sed -e 's/o/me/' stuff | grep ^

파이프 라인의 종료 상태는 해당 파이프 라인에서 마지막 명령의 종료 상태입니다. 따라서 위의 명령은 실제로 find및 의 상태를 완전히 숨기고 최종적으로 성공 sed했는지 여부 만 알려줍니다 grep.

(물론 Bash는 set -o pipefail;하지만 데비안 패키지 스크립트는 Bash 기능을 사용할 수 없습니다. 정책 sh은 이러한 스크립트 에 POSIX 를 사용하도록 강력하게 규정하고 있지만 항상 그런 것은 아닙니다.)

많은 상황에서 이것은 방어 적으로 코딩 할 때 별도로주의해야 할 사항입니다. 때로는 예를 들어 임시 파일을 통해 가야하므로 관용구와 편의가 쉘 파이프 라인을 사용하도록 지시하더라도 출력을 생성 한 명령이 성공적으로 완료되었는지 확인할 수 있습니다.


답변

Script 1: without setting -e
#!/bin/bash
decho "hi"
echo "hello"
This will throw error in decho and program continuous to next line

Script 2: With setting -e
#!/bin/bash
set -e
decho "hi"
echo "hello"
# Up to decho "hi" shell will process and program exit, it will not proceed further