command_1
대부분의 Linux 가이드에는 "을 실행 한 다음 을 실행 command_2
한 다음 을 실행해야 합니다 command_3
." 와 같은 페이지가 포함되어 있습니다 . 이 모든 작업을 수동으로 실행하는 데 시간을 낭비하고 싶지 않기 때문에 스크립트를 만드는 것이 좋습니다.
command_1
command_2
command_3
그리고 한 번 실행해 보세요. 그러나 종종 일부 명령이 실패하고 어떤 명령이 실패했는지 알 수 없습니다. 또한 이전에 오류가 발생하면 일반적으로 나머지 명령은 모두 의미가 없습니다. 따라서 더 나은 스크립트는 다음과 같습니다.
(command_1 && echo OK command_1 || (echo FAILED command_1; false) )
&& (command_2 && echo OK command_2 || (echo FAILED command_2; false) )
&& (command_3 && echo OK command_3 || (echo FAILED command_3; false) )
&& echo DONE
|| echo FAILED
하지만 너무 많은 상용구 코드를 작성해야 하고 각 명령을 3번 반복해야 하며 일부 중괄호를 잘못 입력할 가능성이 높습니다. 마지막 스크립트가 수행한 작업을 수행하는 더 편리한 방법이 있습니까? 특히:
- 명령을 순서대로 실행
- 명령이 실패하면 중단
- 어떤 명령이 실패했는지 기록하세요(있는 경우).
- 명령과의 정상적인 상호 작용을 허용합니다. 모든 출력이 인쇄되고 키보드 입력이 허용됩니다(명령이 무엇이든 요구하는 경우).
답변 요약(2020년 1월 2일)
솔루션에는 두 가지 유형이 있습니다.
- 수정 없이 가이드의 복사-붙여넣기 명령을 허용하지만 실패한 명령을 인쇄하지 않는 것입니다. 따라서 실패한 명령이 긴 출력을 생성하는 경우 어떤 명령이 실패했는지 확인하려면 많은 줄을 위로 스크롤해야 합니다. (모두 인기있는 답변)
- 마지막 줄을 인쇄하는 것은 실패하지만 복사하여 붙여넣은 후 따옴표를 추가하거나(John의 답변) 명령문 을 추가
try
하고 연결된 명령을 별도의 명령으로 분할(Jasen의 답변)하여 명령을 수정해야 합니다.
너희들은 정말 대단하지만 나는 이 이야기를 잠시 제쳐두겠습니다. 어쩌면 누군가가 두 가지 요구 사항을 모두 충족하는 솔루션(마지막 줄에 실패한 명령을 인쇄하고 수정 없이 명령을 복사하여 붙여넣을 수 있음)을 알고 있을 수도 있습니다.
답변1
한 가지 옵션은 명령을 bash 스크립트에 넣고 set -e
.
0이 아닌 종료 상태로 명령이 종료되면 스크립트가 조기에 종료됩니다.
Stack Overflow에 대한 이 질문도 참조하세요.https://stackoverflow.com/q/19622198/828193
오류를 인쇄하려면 다음을 사용할 수 있습니다.
trap 'do_something' ERR
do_something
오류를 표시하기 위해 생성할 명령은 어디에 있습니까?
다음은 작동 방식을 확인할 수 있는 예제 스크립트입니다.
#!/bin/bash
set -e
trap 'echo "******* FAILED *******" 1>&2' ERR
echo 'Command that succeeds' # this command works
ls non_existent_file # this should fail
echo 'Unreachable command' # and this is never called
# due to set -e
출력은 다음과 같습니다.
$ ./test.sh
Command that succeeds
ls: cannot access 'non_existent_file': No such file or directory
******* FAILED *******
또한, 언급한 바와 같이@지케, 파이프의 종료 상태는 기본적으로 파이프의 종료 상태로 설정된다는 점을 기억하세요.결정적인명령이 그 안에 있습니다. 이는 파이프라인의 최종이 아닌 명령이 실패하더라도 차단되지 않음을 의미합니다 set -e
. 이 문제를 해결하려면(걱정되는 경우) 다음을 사용할 수 있습니다.set -o pipefail
내가 제안한대로@glennjackman그리고@몬티하드, 함수를 핸들러로 사용하면 중첩된 참조를 방지하므로 스크립트를 더 쉽게 읽을 수 있습니다. 어쨌든 우리는 함수를 사용하고 있기 때문에 set -e
함수를 완전히 제거하고 exit 1
처리기에서 사용했습니다. 그러면 일부 사람들이 더 쉽게 읽을 수 있습니다.
#!/bin/bash
error_handler() {
echo "******* FAILED *******" 1>&2
exit 1
}
trap error_handler ERR
echo 'Command that succeeds' # this command works
ls non_existent_file # this should fail
echo 'Unreachable command' # and this is never called
# due to the exit in the handler
스크립트의 종료 상태는 다르지만 출력은 위와 동일합니다.
답변2
특이한 솔루션을 원하시나요? 설치 되어 있으면 make
명령 목록을 Makefile
for 에 넣어 make
실행할 수 있습니다. 추가 이점: 오류가 발생했는지 확인할 필요가 없습니다. make
각 명령의 반환 값은 자동으로 확인됩니다. 0이 아닌 경우 레시피는 오류와 함께 종료됩니다. 특정 명령에 대한 오류를 무시하려면 해당 명령을 와 결합하십시오 || true
.
메이크파일 예:
.PHONY: all
.SILENT:
all:
echo "Started list of commands."
true
echo "Executing a command which will fail, but I want to ignore failure."
false || true
echo "Executing a command which will definitely fail."
false
echo "This code will not be reached."
참고: 위와 같이 명령을 들여쓰기하되 탭을 사용해야 합니다.
답변3
나는 이것이 bash에서만 작동한다고 생각하지만 다음을 시도해 볼 수 있습니다.
set -o xtrace
set -o errexit
혹은 좀 더 간결하게 하고 싶다면,
set -ex
이는 두 가지 작업을 수행합니다. errexit
(-e)는 오류 발생 시 스크립트를 중단하고, xtrace
(-x)는 bash가 실행하기 전에 각 명령을 인쇄하므로 실패할 경우 실행 중인 내용을 정확히 알 수 있습니다.
한 가지 단점은 출력이 복잡하다는 점이지만 동의하는 한 최소한의 작업만 필요로 하는 매우 좋은 솔루션입니다.
- 이 작업을 수행할 때 일반적으로 다음을 포함하는 것이 좋습니다
set -o pipefail
. 그렇지 않고 를 실행하면foo | bar
실패가foo
자동으로 무시됩니다. (경고: 파이프 문의 "종료 코드"를 미묘하게 변경하므로 다른 사람의 스크립트를 수정하는 경우 주의해서 사용하십시오. 또한 때로는foo
실제로 신경 쓰지 않는 실패가 있으므로 분명히 할 수 없습니다.pipefail
이 경우에 사용하세요 .)
답변4
failed=0
try(){
(( failed )) && return
"$@"
ec=$?
if (( ec ))
then
failed=$ec
echo "failed($failed): $*" >&2
fi
}
try something args
try other-thing more args
if (( failed ))
then
echo "something went wrong: see above." >&2
exit 1
fi