'set -e'는 무엇을하며 왜 위험한 것으로 간주 될 수 있습니까?


147

이 질문은 사전 인터뷰 퀴즈에 나타 났으며 저를 미치게 만들었습니다. 누구든지 이것에 대답하고 편하게 해줄 수 있습니까? 퀴즈에는 특정 셸에 대한 참조가 없지만 작업 설명은 유닉스 sa에 대한 것입니다. 다시 질문은 간단합니다 ...

'set -e'는 무엇을하며 왜 위험한 것으로 간주 될 수 있습니까?


답변:


154

set -e 부속 명령 또는 파이프 라인이 0이 아닌 상태를 리턴하면 쉘이 종료됩니다.

면접관이 찾고 있던 대답은 다음과 같습니다.

init.d 스크립트를 생성 할 때 "set -e"를 사용하는 것은 위험합니다 :

에서 http://www.debian.org/doc/debian-policy/ch-opersys.html 9.3.2 -

init.d 스크립트에서 set -e를 사용하도록주의하십시오. 올바른 init.d 스크립트를 작성하려면 데몬이 init.d 스크립트를 중단하지 않고 이미 실행 중이거나 이미 중지 된 경우 다양한 오류 종료 상태를 승인해야하며 일반적인 init.d 함수 라이브러리는 set -e를 사용하여 호출하기에 안전하지 않습니다. init.d 스크립트의 경우 종종 set -e를 사용하지 않고 대신 각 명령의 결과를 개별적으로 확인하는 것이 더 쉽습니다.

이는 서버 레벨 스크립팅 및 자동화에 대한 실무 지식을 측정하기 때문에 면접관 관점에서 유효한 질문입니다.


좋은 지적. 기술적으로 오류가있을 수있는 부팅 프로세스를 중단시킬 수 있지만 전체 스크립트가 중지되지 않아야합니다.
Matt

비록 stackoverflow.com/questions/78497/…에 동의하지만 ,이 스타일은 대상 워크로드를 실행하기 전에 짧은 초기화 점검 및 로깅 또는 기타 환경 원숭이 패치에 bash와 잘 맞는다고 생각합니다. 초기화 스크립트.
joshperry

33

보낸 사람 bash(1):

          -e      Exit immediately if a pipeline (which may consist  of  a
                  single  simple command),  a subshell command enclosed in
                  parentheses, or one of the commands executed as part  of
                  a  command  list  enclosed  by braces (see SHELL GRAMMAR
                  above) exits with a non-zero status.  The shell does not
                  exit  if  the  command that fails is part of the command
                  list immediately following a  while  or  until  keyword,
                  part  of  the  test  following  the  if or elif reserved
                  words, part of any command executed in a && or  ││  list
                  except  the  command  following  the final && or ││, any
                  command in a pipeline but the last, or if the  command’s
                  return  value  is being inverted with !.  A trap on ERR,
                  if set, is executed before the shell exits.  This option
                  applies to the shell environment and each subshell envi-
                  ronment separately (see  COMMAND  EXECUTION  ENVIRONMENT
                  above), and may cause subshells to exit before executing
                  all the commands in the subshell.

불행히도 "스크립트의 나머지 부분은 실행되지 않을 것"또는 "아마도 실제 문제를 숨길 수 있습니다"를 제외하고 왜 위험한지 생각할만큼 창의적이지 않습니다.


1
실제 / 다른 문제를
숨기

에 대한 맨 페이지가 있습니다 set! 나는 항상에 끝납니다 builtin(1). 감사.
Jared Beck

??에 대한 문서 set가 있음을 어떻게 알 수 있습니까 man 1 bash?? 어떻게 매뉴얼 페이지에서 키워드에 -e대한 옵션 을 찾을 수 set있을까요? 당신은 캔트 /-e검색
phil294

@Blauhirn 사용help set
phil294

19

주목해야한다 set -e스크립트의 다양한 섹션을 위해 켜거나 끌 수 있습니다. 전체 스크립트 실행을 위해 켜져 있지 않아도됩니다. 조건부로 활성화 할 수도 있습니다. 즉, 내 자신의 오류 처리를 수행하거나 사용하지 않으므로 사용하지 않습니다.

some code
set -e     # same as set -o errexit
more code  # exit on non-zero status
set +e     # same as set +o errexit
more code  # no exit on non-zero status

또한 특정 상황에서 trap어떻게 set -e작동 하는지 설명하는 명령 의 Bash 매뉴얼 페이지 섹션에서 주목할 만하다 .

실패한 명령이 while 또는 until 키워드 바로 다음에 오는 명령 목록의 일부이거나, if 문의 테스트 부분, && 또는 ⎪⎪ 목록에서 실행 된 명령의 일부이거나, 명령의 경우에는 ERR 트랩이 실행되지 않습니다. !를 통해 반환 값이 반전됩니다. 이것은 errexit 옵션이 준수하는 것과 동일한 조건입니다.

따라서 0이 아닌 상태가 종료되지 않는 조건이 있습니다.

나는 위험에 처 set -e했을 때와 그것이 맞지 않을 때 어떤 잘못된 가정 하에서 잘못 이해하고있을 때 위험을 이해하지 못한다고 생각합니다 .

BashFAQ / 105 도 참조하십시오. -e (또는 set -o errexit 또는 trap ERR)를 설정하지 않은 이유는 무엇입니까?


질문에서 조금 벗어나 면서이 답변은 내가 찾고있는 것입니다 : 스크립트의 작은 부분에 대해서만 끄십시오!
Stephan Bijzitter

13

이것은 면접을위한 퀴즈입니다. 질문은 현재 직원이 작성했을 수 있으며 잘못되었을 수 있습니다. 이것은 반드시 나쁘지는 않으며, 모든 사람이 실수를 저지르고 인터뷰 질문은 종종 검토없이 어두운 구석에 앉아 인터뷰 중 나옵니다.

'set -e'가 우리가 "위험한"것으로 간주하지 않는 것은 전적으로 가능합니다. 그러나이 질문의 저자는 자신의 무지 나 편견 때문에 'set-e'가 위험하다고 잘못 생각할 수 있습니다. 어쩌면 그들은 버그가 많은 쉘 스크립트를 작성했고, 끔찍하게 폭탄을 터뜨 렸으며, 실제로 올바른 오류 검사를 작성하지 않으면 'set -e'가 책임이 있다고 생각했습니다.

지난 2 년간 40 번의 면접에 참여한 적이 있으며, 면접관은 때때로 잘못된 질문을하거나 잘못된 답변을합니다.

아니면 어리석은 질문이지만 완전히 예기치 않은 것은 아닙니다.

또는 이것은 좋은 설명입니다 : http://www.mail-archive.com/debian-bugs-dist@lists.debian.org/msg473314.html


1
+1 나는 같은 배에 있고, 내가 다루고있는 많은 '기술적 인'인터뷰는 적어도 약간 잘못 인도되었다.
cpbills

1
와. 데비안 목록에서 찾으십시오. 면접 질문의 무지에 +1. 내가 옳았다 고 100 % 확신했기 때문에 네트 백 답변을 한 번 주장한 것을 기억합니다. 그들은 말했다. 집에 가서 봤어요.
egorgry

9

set -e 스크립트에서 bash가 0이 아닌 리턴 값을 리턴 할 때마다 종료하도록 지시합니다.

나는 당신이 무언가에 대한 권한을 열지 않고 다시 제한하기 전에 스크립트가 죽는 것이 어떻게 귀찮고 버그가 있는지 위험에 대해 확신하지 못하는 것을 알 수있었습니다.


그 흥미 롭군요. 나는 조기에 죽는 스크립트에서 권한이 열리지 않았다고 생각했지만 위험한 것으로 간주됩니다. 이 퀴즈의 재미있는 부분은 man 또는 google과 같은 참조 자료를 사용할 수 없으며 완전히 대답 할 수 없으면 전혀 대답하지 않는 것입니다.
egorgry

6
그건 멍청한 짓이야,이 고용주를 재검토 하겠어. 농담이야. 강력한 지식 기반을 갖는 것이 좋지만 IT 작업의 절반은 정보를 찾을 수있는 위치 / 위치를 알고 있습니다. 참고로, / no / use for set -e, 실제로는 스크립트에서 오류 확인을 무시하는 게으름에 대해 말합니다 ... 그래서이 고용주에게도 명심하십시오. 많은, 그들의 스크립트가 어떻게 생겼는지, 필연적으로 유지해야 할 것입니다 ...
cpbills

우수 포인트 @cpbills. 또한 스크립트에서 set -e를 사용하지 않는 것을 보았을 것입니다. 일부는 정말 훌륭하고 일부는 정말 엉뚱하고 무작위이기 때문에 모든 질문을 게시하고 싶습니다.
egorgry

나는 많은 시스템 크론 작업에서 그것을 보았습니다 ...
Andrew

8

set -e특정 조건을 제외하고 0이 아닌 종료 코드가 발견되면 스크립트를 종료합니다. 몇 마디로 사용의 위험성을 요약하면 사람들이 생각하는대로 행동하지 않습니다.

제 생각에는 호환성 목적으로 만 존재하는 위험한 핵으로 간주해야합니다. 이 set -e문장은 오류 코드를 사용하는 언어에서 예외와 같은 제어 흐름을 사용하는 언어로 쉘을 바꾸지 않고 단지 그 행동을 모방하려는 시도를 잘못합니다.

Greg Wooledge는 다음과 같은 위험에 대해 많은 의견을 가지고 있습니다 set -e.

두 번째 링크에는의 직관적이지 않고 예측할 수없는 동작에 대한 다양한 예가 set -e있습니다.

직관적이지 않은 동작의 일부 예 set -e(위의 wiki 링크에서 가져온 것) :

  • 세트 -e
    x = 0
    x ++하자
    에코 "x는 $ x"
    위의 let x++결과는 let키워드에 의해 잘못된 값으로 취급되고 0이 아닌 종료 코드로 바뀌는 0을 리턴 하므로 쉘 스크립트가 조기에 종료 됩니다. set -e이를 확인하고 스크립트를 자동으로 종료합니다.
  • 세트 -e
    [-d / opt / foo] && echo "경고 : foo가 이미 설치되어 있습니다. 덮어 씁니다." > & 2
    echo "foo 설치 중 ..."
    

    위의 내용은 예상대로 작동 /opt/foo하며 이미 존재 하는 경우 경고를 인쇄합니다 .

    세트 -e
    check_previous_install () {
        [-d / opt / foo] && echo "경고 : foo가 이미 설치되어 있습니다. 덮어 씁니다." > & 2
    }
    
    check_previous_install
    echo "foo 설치 중 ..."
    

    위의 내용은 단일 라인이 함수로 리팩토링되었다는 유일한 차이점에도 불구하고 /opt/foo존재하지 않으면 종료됩니다 . 원래 작동했다는 사실이 set -e의 행동에 대한 특별한 예외이기 때문 입니다. a && b0이 아닌 값을 반환 하면 로 무시됩니다 set -e. 그러나 이제는 함수이므로 함수의 종료 코드는 해당 명령의 종료 코드와 동일하며 0이 아닌 값을 반환하는 함수는 자동으로 스크립트를 종료합니다.

  • 세트 -e
    IFS = $ '\ n'읽기 -d ''-r -a config_vars <구성
    

    위의 내용은 config_vars파일 에서 배열 을 읽습니다 config. 작성자가 의도 한대로 config누락 된 경우 오류와 함께 종료됩니다 . 저자가 의도 config하지 않은 것처럼 , 개행으로 끝나지 않으면 자동으로 종료됩니다 . set -e여기에서 사용되지 않은 경우 config_vars파일이 줄 바꿈으로 끝나는 지 여부에 관계없이 파일의 모든 줄을 포함합니다.

    Sublime Text (및 개행을 잘못 처리하는 다른 텍스트 편집기) 사용자는주의하십시오.

  • 세트 -e
    
    should_audit_user () {
        로컬 그룹 그룹 = "$ (그룹"$ 1 ")"
        $ groups의 그룹; 하다
            [ "$ group"= audit] 인 경우; 그런 다음 0을 반환합니다. fi
        끝난
        1을 반환
    }
    
    should_audit_user "$ user"이면; 그때
        로거 'Blah'
    fi
    

    여기서 저자는 어떤 이유로 사용자 $user가 존재하지 않으면 groups명령이 실패하고 사용자가 감사 하지 않은 일부 작업을 수행하도록하는 대신 스크립트가 종료 될 것으로 예상 할 수 있습니다 . 그러나이 경우 set -e종료는 적용되지 않습니다. $user어떤 이유로 스크립트를 종료하지 않고 찾을 수없는 경우 , should_audit_user함수는 마치 set -e유효하지 않은 것처럼 잘못된 데이터를 반환 합니다.

    이것은 if명령문 의 조건 부분에서 호출 된 함수에 관계없이, 얼마나 깊이 중첩되어 있든지, 정의 된 위치에 관계없이 set -e다시 실행하더라도 상관없이 적용 됩니다. if어느 시점에서나 사용 set -e하면 조건 블록이 완전히 실행될 때까지의 효과가 완전히 비활성화 됩니다. 작성자가이 함정을 인식하지 못하거나 함수를 호출 할 수있는 모든 가능한 상황에서 전체 호출 스택을 알지 못하면 버그가있는 코드를 작성하고 제공되는 잘못된 보안 감각은 set -e적어도 부분적으로 비난.

    저자가이 함정을 완전히 알고 있더라도 해결 방법은 코드를 사용하지 않고 코드를 작성하는 것과 같은 방식으로 코드를 작성하는 것입니다 set -e. 저자는 set -e효과가없는 것처럼 수동 오류 처리 코드를 작성해야 할 뿐만 아니라 존재하는 것으로 set -e인해 필요하지 않다고 생각하게 만들 수도 있습니다.

몇 가지 추가 단점 set -e:

  • 조잡한 코드를 권장합니다. 오류 처리기는 오류가 발생했을 때 오류를 합리적인 방식으로보고하기를 희망하면서 완전히 잊혀졌습니다. 그러나 let x++위와 같은 예 에서는 그렇지 않습니다. 스크립트가 예기치 않게 종료되면 일반적으로 자동으로 실행되므로 디버깅에 방해가됩니다. 스크립트가 죽지 않고 예상 한 경우 (이전 글 머리표 참조) 더 미묘하고 교묘 한 버그가 있습니다.
  • 사람들을 잘못된 보안 감각으로 인도합니다. - if조건 글 머리 기호를 다시 참조하십시오 .
  • 쉘이 종료되는 위치는 쉘 또는 쉘 버전간에 일치하지 않습니다. 이전 버전의 bash set -e에서 해당 버전간에 조정 된 동작으로 인해 다르게 작동하는 스크립트를 실수로 작성할 수 있습니다.

set -e논쟁의 여지가있는 문제이며, 어떤 사람들은 그 문제에 대한 주변의 문제를 알고 있지만, 어떤 사람들은 함정을 잘 알고있는 동안 돌보는 것을 권장합니다. set -e모든 스크립트에서 오류 조건에 대한 포괄적 인 것으로 추천 하는 많은 쉘 스크립팅 초보자가 있지만 실제로는 그렇게 작동하지 않습니다.

set -e 교육을 대신 할 수 없습니다.


2

나는 당신이 더 이상 스크립트의 흐름을 제어하지 않기 때문에 위험하다고 말합니다. 스크립트가 호출하는 명령이 0이 아닌 값을 반환하는 한 스크립트를 종료 할 수 있습니다. 따라서 구성 요소의 동작이나 출력을 변경하는 작업을 수행하면 주 스크립트를 종료 할 수 있습니다. 스타일 문제 일 수 있지만 결과는 확실합니다. 주 스크립트가 플래그를 설정해야하는데 초기에 종료되지 않았기 때문에 어떻게해야합니까? 플래그가 있어야한다고 가정하거나 예기치 않은 기본값 또는 이전 값으로 작업하면 시스템의 나머지 부분에 오류가 발생합니다.


이 답변에 전적으로 동의하십시오. 그것은 아니다 본질적으로 위험하지만, 예상치 못한 조기 종료를 할 수있는 기회입니다.
pboin

1
이것이 내가 생각 나게 한 것은 프로그램에 단일 진입 점 / 단일 종료 점이 없기 때문에 항상 과제에서 포인트를 가져 오는 C ++ 교수입니다. 나는 그것이 순전히 '원리'일 것이라고 생각했지만,이 세트 사업은 사물이 완전히 통제에서 벗어날 수있는 방법과 이유를 분명히 보여줍니다. 궁극적으로 프로그램은 제어 및 결정론에 관한 것이며 조기 종료를 통해 둘 다를 포기합니다.
Marcin

0

개인적으로 나를 물린 @Marcin의 대답에 대한보다 구체적인 예로써, rm foo/bar.txt당신의 스크립트 어딘가에 줄 이 있다고 상상해보십시오 . foo/bar.txt실제로 존재하지 않는 경우 일반적으로 큰 문제 가 없습니다. 그러나 set -e현재는 스크립트가 일찍 종료됩니다! 죄송합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.