답변 요약(2020년 1월 2일)

답변 요약(2020년 1월 2일)

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명령 목록을 Makefilefor 에 넣어 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

관련 정보