Linux의 Bash 스크립트에서 set 및 pipefail을 사용하는 방법

게시 됨: 2022-06-25
파란색 배경 위에 노트북 화면의 Linux 터미널.
Fatmawati achmad zaenuri/Shutterstock.com

Linux setpipefail 명령은 Bash 스크립트에서 오류가 발생할 때 어떤 일이 발생하는지 지시합니다. 중단해야 하거나 계속해야 하는 것보다 생각해야 할 것이 더 많습니다.

관련: 셸 스크립팅에 대한 초보자 가이드: 기본 사항

Bash 스크립트 및 오류 조건

Bash 쉘 스크립트는 훌륭합니다. 그들은 작성이 빠르고 컴파일이 필요하지 않습니다. 수행해야 하는 반복적이거나 다단계 작업을 편리한 스크립트로 래핑할 수 있습니다. 그리고 스크립트는 표준 Linux 유틸리티를 호출할 수 있기 때문에 쉘 언어 자체의 기능에 제한되지 않습니다.

그러나 외부 유틸리티나 프로그램을 호출할 때 문제가 발생할 수 있습니다. 실패하면 외부 유틸리티가 닫히고 반환 코드를 셸로 보내고 터미널에 오류 메시지를 인쇄할 수도 있습니다. 그러나 스크립트는 계속 처리됩니다. 아마도 그것은 당신이 원하는 것이 아닙니다. 스크립트 실행 초기에 오류가 발생하는 경우 스크립트의 나머지 부분이 실행되도록 허용되면 문제가 더 악화될 수 있습니다.

Bash 셸이란 무엇이며 Linux에 왜 중요한가요?
관련 Bash 셸이란 무엇이며 Linux에 왜 중요한가요?

완료되면 각 외부 프로세스의 반환 코드를 확인할 수 있지만 프로세스가 다른 프로세스로 파이프되면 어려워집니다. 반환 코드는 중간에 실패한 프로세스가 아니라 파이프 끝에 있는 프로세스에서 가져온 것입니다. 물론 초기화되지 않은 변수에 액세스하려는 것과 같이 스크립트 내부에서도 오류가 발생할 수 있습니다.

setpipefile 명령을 사용하면 이와 같은 오류가 발생할 때 어떤 일이 발생하는지 결정할 수 있습니다. 또한 파이프 체인 중간에서 오류가 발생한 경우에도 오류를 감지할 수 있습니다.

사용 방법은 다음과 같습니다.

문제 시연

다음은 간단한 Bash 스크립트입니다. 터미널에 두 줄의 텍스트를 에코합니다. 텍스트를 편집기에 복사하여 "script-1.sh"로 저장하면 이 스크립트를 실행할 수 있습니다.

 #!/bin/bash

echo 이것은 먼저 일어날 것입니다 
echo 이것은 두 번째로 일어날 것입니다

실행 가능하게 하려면 chmod 를 사용해야 합니다.

 chmod +x 스크립트-1.sh

컴퓨터에서 실행하려면 각 스크립트에서 해당 명령을 실행해야 합니다. 스크립트를 실행해 보겠습니다.

 ./스크립트-1.sh 

오류 없이 간단한 스크립트를 실행합니다.

예상대로 두 줄의 텍스트가 터미널 창으로 전송됩니다.

스크립트를 약간 수정해 보겠습니다. 존재하지 않는 파일의 세부 정보를 나열하도록 ls 에 요청할 것입니다. 이것은 실패합니다. 이것을 "script-2.sh"로 저장하고 실행 가능하게 만들었습니다.

 #!/bin/bash

echo 이것은 먼저 일어날 것입니다
ls 가상 파일 이름
echo 이것은 두 번째로 일어날 것입니다

이 스크립트를 실행하면 ls 의 오류 메시지가 표시됩니다.

 ./스크립트-2.sh 

스크립트를 실행하고 실패 조건을 생성합니다.

ls 명령이 실패했지만 스크립트는 계속 실행되었습니다. 그리고 스크립트 실행 중에 오류가 발생하더라도 스크립트에서 쉘로의 리턴 코드는 0으로 성공을 나타냅니다. echo와 $? 를 사용하여 확인할 수 있습니다. 쉘로 보낸 마지막 리턴 코드를 보유하는 변수.

 에코 $? 

마지막으로 실행된 스크립트의 반환 코드를 확인합니다.

보고되는 0은 스크립트의 두 번째 에코에서 반환되는 코드입니다. 따라서 이 시나리오에는 두 가지 문제가 있습니다. 첫 번째는 스크립트에 오류가 있었지만 계속 실행되었다는 것입니다. 스크립트의 나머지 부분이 실패한 작업이 실제로 성공한 것으로 예상하거나 의존하는 경우 다른 문제가 발생할 수 있습니다. 그리고 두 번째는 다른 스크립트나 프로세스가 이 스크립트의 성공 또는 실패를 확인해야 하는 경우 잘못된 판독을 얻게 된다는 것입니다.

set -e 옵션

set -e (종료) 옵션은 스크립트가 호출하는 프로세스에서 0이 아닌 리턴 코드를 생성하는 경우 스크립트가 종료되도록 합니다. 0이 아닌 모든 것은 실패로 간주됩니다.

스크립트 시작 부분에 set -e 옵션을 추가하여 동작을 변경할 수 있습니다. "script-3.sh"입니다.

 #!/bin/bash 
세트 -e

echo 이것은 먼저 일어날 것입니다
ls 가상 파일 이름
echo 이것은 두 번째로 일어날 것입니다

이 스크립트를 실행하면 set -e 의 효과를 볼 수 있습니다.

 ./스크립트-3.sh
 에코 $? 

오류 조건에서 스크립트를 종료하고 반환 코드를 올바르게 설정합니다.

스크립트가 중지되고 셸로 보내진 반환 코드는 0이 아닌 값입니다.

파이프 실패 처리

배관은 문제를 더 복잡하게 만듭니다. 파이프된 명령 시퀀스에서 나오는 반환 코드는 체인의 마지막 명령에서 나온 반환 코드입니다. 체인 중간에 명령이 실패하면 다시 원점으로 돌아갑니다. 해당 반환 코드는 손실되고 스크립트는 처리를 계속합니다.

truefalse 쉘 내장 기능을 사용하여 서로 다른 리턴 코드로 파이프 명령의 효과를 볼 수 있습니다. 이 두 명령은 각각 0 또는 1의 반환 코드를 생성합니다.

 진실
 에코 $?
 거짓
 에코 $? 

bash 셸 true 및 false 기본 제공 명령.

falsetrue 로 파이프하면(실패한 프로세스를 나타내는 false 와 함께) true 의 반환 코드가 0이 됩니다.

 거짓 | 진실
 에코 $? 

거짓을 참으로 연결합니다.

Bash에는 PIPESTATUS 라는 배열 변수가 있으며 이것은 파이프 체인의 각 프로그램에서 모든 반환 코드를 캡처합니다.

 거짓 | 사실 | 거짓 | 진실
 echo "${PIPESTATUS[0]} ${PIPESTATUS[1]} ${PIPESTATUS[2]} ${PIPESTATUS[3]}" 

PIPESTATUS를 사용하여 파이프 체인에 있는 모든 프로그램의 반환 코드를 봅니다.

PIPESTATUS 는 다음 프로그램이 실행될 때까지만 반환 코드를 보유하고 어떤 반환 코드가 어떤 프로그램과 함께 가는지 결정하려고 하면 매우 빠르게 지저분해질 수 있습니다.

여기에서 set -o (옵션)와 pipefail 이 사용됩니다. 이것은 "script-4.sh"입니다. 이것은 존재하지 않는 파일의 내용을 wc 로 파이프하려고 시도합니다.

 #!/bin/bash 
세트 -e

echo 이것은 먼저 일어날 것입니다
고양이 스크립트-99.sh | 화장실 -l
echo 이것은 두 번째로 일어날 것입니다

예상대로 실패합니다.

 ./스크립트-4.sh
 에코 $? 

파이프 체인에서 오류가 있는 스크립트 실행.

첫 번째 0은 wc 의 출력으로, 누락된 파일에 대한 행을 읽지 않았음을 알려줍니다. 두 번째 0은 두 번째 echo 명령의 반환 코드입니다.

-o pipefail 을 추가하고 "script-5.sh"로 저장하고 실행 가능하게 만듭니다.

 #!/bin/bash 
set -eo 파이프 실패

echo 이것은 먼저 일어날 것입니다
고양이 스크립트-99.sh | 화장실 -l
echo 이것은 두 번째로 일어날 것입니다

그것을 실행하고 리턴 코드를 확인합시다.

 ./스크립트-5.sh
 에코 $? 

파이프 체인의 오류를 트래핑하고 반환 코드를 올바르게 설정하는 스크립트를 실행합니다.

스크립트가 중지되고 두 번째 echo 명령이 실행되지 않습니다. 셸로 보낸 반환 코드는 1이며 올바르게 실패를 나타냅니다.

관련: Linux에서 Echo 명령을 사용하는 방법

초기화되지 않은 변수 잡기

초기화되지 않은 변수는 실제 스크립트에서 찾기 어려울 수 있습니다. 초기화되지 않은 변수의 값을 echo 하려고 하면 echo 는 단순히 빈 줄을 인쇄합니다. 오류 메시지를 표시하지 않습니다. 나머지 스크립트는 계속 실행됩니다.

이것은 script-6.sh입니다.

 #!/bin/bash 
set -eo 파이프 실패

echo "$notset" 
echo "또 다른 에코 명령"

우리는 그것을 실행하고 그 동작을 관찰할 것입니다.

 ./스크립트-6.sh
 에코 $? 

초기화되지 않은 변수를 캡처하지 않는 스크립트를 실행합니다.

스크립트는 초기화되지 않은 변수를 단계별로 실행하고 계속 실행합니다. 반환 코드는 0입니다. 매우 길고 복잡한 스크립트에서 이와 같은 오류를 찾는 것은 매우 어려울 수 있습니다.

Bash에서 변수로 작업하는 방법
관련 Bash에서 변수로 작업하는 방법

set -u (unset) 옵션을 사용하여 이러한 유형의 오류를 트래핑할 수 있습니다. 이를 스크립트 상단에 있는 세트 옵션 모음에 추가하고 "script-7.sh"로 저장하고 실행 가능하게 만들 것입니다.

 #!/bin/bash 

set -eou 파이프 실패

echo "$notset" 

echo "또 다른 에코 명령"

스크립트를 실행해 보겠습니다.

 ./스크립트-7.sh
 에코 $? 

초기화되지 않은 변수를 캡처하는 스크립트를 실행합니다.

초기화되지 않은 변수가 감지되고 스크립트가 중지되고 반환 코드가 1로 설정됩니다.

-u (설정되지 않음) 옵션은 초기화되지 않은 변수와 합법적으로 상호 작용할 수 있는 상황에 의해 트리거되지 않을 만큼 지능적입니다.

"script-8.sh"에서 스크립트는 변수 New_Var 가 초기화되었는지 여부를 확인합니다. 스크립트가 여기서 멈추는 것을 원하지 않습니다. 실제 스크립트에서는 추가 처리를 수행하고 상황을 직접 처리하게 됩니다.

set 문의 두 번째 옵션으로 -u 옵션을 추가했습니다. -o pipefail 옵션은 마지막에 와야 합니다.

 #!/bin/bash 

set -euo pipefail

if [ -z "${New_Var:-}" ]; 그 다음에 

echo "New_Var에 할당된 값이 없습니다." 

파이

"script-9.sh"에서는 초기화되지 않은 변수를 테스트하고 초기화되지 않은 경우 기본값을 대신 제공합니다.

 #!/bin/bash
set -euo pipefail

default_value=484
값=${New_Var:-$default_value}
echo "New_Var=$값"

스크립트는 완료될 때까지 실행할 수 있습니다.

 ./스크립트-8.sh
 ./스크립트-9.sh 

초기화되지 않은 변수가 내부적으로 처리되고 -u 옵션이 트리거되지 않는 두 개의 스크립트를 실행합니다.

도끼로 봉인

또 다른 편리한 옵션은 set -x (실행 및 인쇄) 옵션입니다. 스크립트를 작성할 때 이것은 생명의 은인이 될 수 있습니다. 실행될 때 명령과 해당 매개변수를 인쇄합니다.

빠른 "거칠고 준비된" 형태의 실행 추적을 제공합니다. 논리 결함을 분리하고 버그를 찾는 것이 훨씬 더 쉬워집니다.

set -x 옵션을 "script-8.sh"에 추가하고 "script-10.sh"로 저장한 다음 실행 가능하게 만듭니다.

 #!/bin/bash
set -euxo pipefail

if [ -z "${New_Var:-}" ]; 그 다음에
  echo "New_Var에 할당된 값이 없습니다."
파이

추적 라인을 보려면 실행하십시오.

 ./스크립트-10.sh 

터미널에 기록된 -x 추적 라인으로 스크립트 실행.

이러한 사소한 예제 스크립트에서 버그를 찾는 것은 쉽습니다. 더 많은 관련 스크립트를 작성하기 시작하면 이러한 옵션이 그 가치를 증명할 것입니다.