내 bash 지식은 약간 녹슬어서(이전에는 그다지 견고하지 않았음) 다음 질문에 대한 답을 찾을 수 없는 것 같습니다.
제목에서 알 수 있듯이 명령이 실행된 후 bash에 의해 0이 아닌 종료 코드가 설정되었는지 확인하는 방법을 알고 싶습니다.진짜오류) 또는 명령을 통해(가능한명령과 목적에 따라 오류를 나타냅니다.
예를 들어, 다음과 같은 매우 간단한 스크립트를 살펴보겠습니다.
#!/bin/bash
string='abc'
grep 'd' <<< "$string"
echo $?
이는 매뉴얼을 읽은 grep
후 예상되는 1을 출력합니다(발췌, 단축된 광산).
종료 상태
일반적으로 종료 상태는 행이 선택된 경우 0, 선택된 행이 없는 경우 1, 오류가 발생한 경우 2입니다. [...]
bash
매뉴얼의 해당 섹션을 읽은 후 문제가 발생했습니다(내가 발췌, 단축 및 강조).
종료 상태
[...]
명령을 찾을 수 없으면 명령을 실행하기 위해 생성된 하위 프로세스는 상태 127을 반환합니다. 명령이 발견되었지만 실행 가능하지 않은 경우 반환 상태는 126입니다.
확장 또는 리디렉션 중 오류로 인해 명령이 실패한 경우 종료 상태는 0보다 큽니다.
셸 내장 명령은 성공하면 상태 0(true)을 반환하고, 실행 중에 오류가 발생하면 0이 아닌 값(false)을 반환합니다. 모든 내장 함수는 종료 상태 2를 반환하여 잘못된 사용법, 일반적으로 잘못된 옵션 또는 누락된 인수를 나타냅니다.
[...]
내 질문은 강조된 진술입니다.
grep
내 스크립트는 일반적으로 실제 오류(예: 권한 부족, 필요한 프로그램을 사용할 수 없음, 리소스 고갈 등)를 구체적으로 처리해야 하지만 위의 예에서는 행이 선택되지 않은 경우 위의 의미에서 오류가 아닙니다. 이는 단순히 입력에 일치하는 문자 시퀀스가 포함되어 있지 않음을 의미합니다.
bash
하지만 매뉴얼의 부분을 문자 그대로 받아들이면 bash
종료 상태 자체를 설정하는 것일 수도 있습니다 1
. 이 섹션에서는 명령을 찾을 수 없거나(exit status 127
) 실행할 수 없는 경우(exit status ) 126
어떤 일이 발생하는지 알 수 있습니다.
내가 이해한 바에 따르면 해당 섹션의 다음 문은 다른 모든 오류가 [1, 255]
bash를 통해 포함 범위 내의 모든 종료 상태에 매핑될 수 있음을 의미합니다. 특히, 이는 종료 상태로 매핑될 수 있습니다 1
. 나는 "명령을 찾을 수 없음"이나 "명령을 실행할 수 없습니다" 외에 수많은 오류가 있다고 믿기 때문에 이것을 주요 문제로 생각하고 있습니다. 예를 들어, 메모리 소진, 파일 핸들 소진, 디스크 읽기 오류로 인한 시간 초과 등으로 인해 명령 실행이 차단될 수 있습니다.
"grep이 일치하는 줄을 찾을 수 없습니다." 오류와 비교하면 다음과 같습니다.진짜심각한 오류로 인해 일반적으로 즉각적인 조치를 위해 관리자에게 이메일이 전송됩니다.
그러나 이제는 두 가지 오류(명령을 실행하여 설정된 0이 아닌 종료 상태와 명령을 실행하려고 시도한 후 bash가 설정한 0이 아닌 종료 상태)를 구별할 수 없는 것 같습니다.
누구든지 나에게 합리적인 해결책을 알려줄 수 있습니까?
유제
연구하는 동안 비슷한 문제가 많이 발생했습니다. 그러나 내가 아는 한 그런 사람은 아무도 없다.정밀한같은 질문.
대신, 대부분의 사람들은 단지명령에서 반환된 0이 아닌 종료 코드를 억제합니다.(내 예에 적용하면 행이 선택되지 않았을 때의 상태 0
가 아닌 종료 상태를 원했습니다 ) 비슷한 솔루션을 얻었습니다 .1
grep
command || true
이것이 그들에게는 받아들여질 수 있지만 나에게는 해결책이 아닙니다.진짜위에서 언급한 오류입니다. 예를 들어, 다음 상황을 고려해보세요.
root@cerberus:~/scripts# { ThisProgramDoesNotExist 2>/dev/null || true; } && { echo "Gotcha!"; }
Gotcha!
root@cerberus:~/scripts#
이는 이 솔루션이 실행 명령의 0이 아닌 종료 상태(또는 "stati"입니까?)뿐만 아니라 시작 명령이 실패할 때 bash가 보고하는 치명적인 오류도 억제하는 방법을 보여줍니다. 이것은 대부분의 스크립트에서 허용되지 않습니다.
답변1
당신은 말할 수 없습니다. 당신이 얻는 것은 0에서 255 사이의 단일 값입니다. 모든 것이 잘되면 0이고 그렇지 않으면 0이 아닙니다.
0이 아닌 일부 상태를 성공으로 간주하려면 관련 명령이 다른 이유로(예: 리디렉션) 실패하지 않는지 확인하세요. 다양한 유형의 오류가 여러 명령에서 발생하거나 다른 상태가 발생하도록 명령을 분류합니다.
예를 들어 오류가 리디렉션으로 인해 발생한 것인지 알아야 하는 경우 별도의 명령으로 리디렉션을 수행하거나 블록을 통해 개별적으로 리디렉션을 수행할 수 있습니다.
전반적인 상태:
mycommand <foo
status=$?
if [ $status -ne 0 ]; then echo "Either mycommand failed or <foo failed"; fi
별도의 상태이지만 리디렉션이 실패할 경우 명령 실행을 피할 수 있는 방법은 없습니다.
{
mycommand
command_status=$?
} <foo
redirection_status=$?
if [ $command_status -ne 0 ]; then echo "mycommand failed"; fi
if [ $redirection_status -ne 0 ]; then echo "<foo failed"; fi
먼저 리디렉션을 수행하십시오. 이러한 방식으로 리디렉션 실패에 대응할 수 있는 것은 bash의 기능입니다. 내장된 리디렉션이 실패하면 exec
POSIX 쉘(POSIX 모드의 bash 포함)이 종료됩니다 .
exec 3<&1 # Save stdin to file descriptor 3
exec <foo # bash keeps going if the redirection fails
redirection_status=$?
mycommand
command_status=$?
exec <&3 # Restore stdin
if [ $command_status -ne 0 ]; then echo "mycommand failed"; fi
if [ $redirection_status -ne 0 ]; then echo "<foo failed"; fi
리디렉션이 실패하면 사실 이후에 파일 설명자를 복원할 필요 없이 하위 쉘에 리디렉션 실패를 포함시킵니다.
(
exec <foo || exit $? # In POSIX sh, "|| exit $?" is redundant.
mycommand
command_status=$?
if [ $command_status -ne 0 ]; then echo "mycommand failed"; fi
)
redirection_status=$?
if [ $redirection_status -ne 0 ]; then echo "<foo failed and mycommand didn't run"; fi
오류가 다른 확장에서 발생하는지 확인해야 하는 경우 확장을 별도로 실행하고 결과를 저장하세요.
매개변수 저장: `mycommand "$(…)" 대신 확장된 결과를 먼저 저장합니다.
foo=$(…) && mycommand "$foo"
더 일반적으로:
foo=$(…)
command_substitution_status=$?
mycommand "$foo"
mycommand_status=$?
할당에 여러 명령 대체가 포함된 경우 해당 상태는 마지막 대체의 상태입니다. 마지막 대체가 성공하면 이전 대체가 실패하더라도 상태는 0입니다.
foo=$(…)
foo_status=$?
bar=$(…)
bar_status=$?
mycommand "$foo" "$bar"
mycommand_status=$?
여러 매개변수를 저장하려면 함수 내에서 배열이나 위치 매개변수를 사용하세요.
args=()
foo=$(…)
foo_status=$?
args+=(-x "$foo")
bar=$(…)
bar_status=$?
args+=(-y "$bar")
mycommand "${args[@]}"
답변2
명령을 실행한 후에 차이점을 알 수 있는 방법이 없습니다. 그러나 경쟁 조건을 수락하면 옵션이 충분할 수 있습니다.
바꾸다
cmd with "$params" and </re/di/rections
당신은 그렇습니다
if : with "$params" and </re/di/rections; then
# expansion and redirections are OK
# let's hope no redirection-relevant paths are deleted or created in the meantime
# and, of course, this does not work well with noclobber
cmd with "$params" and </re/di/rections
else
: error "outside" the command
fi