여기 문자열에 오류가 있을 때 스크립트가 실패하도록 하려면 어떻게 해야 합니까?

여기 문자열에 오류가 있을 때 스크립트가 실패하도록 하려면 어떻게 해야 합니까?

다음과 비슷한 스크립트가 있습니다.

#!/bin/bash
set -euo pipefail
IFS=$'\n\t'

while read -r l; do
    echo "${l}"
done <<< "$(cat input.txt)"

echo Success

이 명령은 cat input.txt내 문제를 단순화하기 위한 예일 뿐입니다.

input.txt덕분에 스크립트가 존재하지 않으면 즉시 종료될 것으로 예상했습니다 set -euo pipefail. 그러나 그렇지 않은 경우 스크립트는 다음 출력으로 성공적으로 종료됩니다.

cat: input.txt: No such file or directory

Success

예상대로 스크립트가 실패하도록 하는 방법이 있습니까?

답변1

나는 이것이 cat input.txt임의의 명령에 대한 자리 표시자라는 것을 알고 있습니다. 특히 cat input.txt해결책은 간단합니다. 입력 리디렉션을 사용하면 됩니다 input.txt.

종료 코드는 여기 문자열의 다음 확장에서 사용할 수 있습니다. 예를 들어:

cat <<< "$(exit 3)$?"

출력 3. 따라서 다음을 수행할 수 있습니다.

#! /bin/bash -
set -o nounset -o pipefail -o errexit

unset -v ret
{
  [ "$ret" -eq 0 ] || exit "$ret"
  while IFS= read -r line || [ -n "$line" ]; do
    printf '%s\n' "$line" || exit
  done
} <<< "$(cat input.txt)"${ret[1+(ret=$?)]}"
echo success

이것은 적어도 bash 5.0에서 작동하는 것 같습니다.

또는 임시 변수를 사용할 수 있습니다.

#! /bin/bash -
set -o nounset -o pipefail -o errexit

output_minus_trailing_newlines=$(cat input.txt)
while IFS= read -r line || [ -n "$line" ]; do
  printf '%s\n' "$line" || exit
done <<< "$output_minus_trailing_newlines"

echo success

두 경우 모두 명령이 실패하면 해당 출력이 처리되지 않습니다.

lastpipe루프가 서브셸에서 실행되는 것을 원하지 않는 경우 파이프와 옵션을 사용할 수도 있습니다.

#! /bin/bash -
set -o nounset -o pipefail -o errexit
shopt -s lastpipe

cat input.txt |
  while IFS= read -r line || [ -n "$line" ]; do
    printf '%s\n' "$line" || exit
  done

echo success

그러면 출력이 처리됩니다. errexit( -e) 및 의 조합 으로 인해 명령이 실패한 경우 파이프가 종료된 후에만 쉘이 종료됩니다 pipefail. 이 경우 후행 빈 줄이 유지됩니다.

동일한 절차로 바꾸십시오.

#! /bin/bash -
set -o nounset -o pipefail -o errexit

{
  pid="$!"
  while IFS= read -r line || [ -n "$line" ]; do
    printf '%s\n' "$line" || exit
  done
  wait "$pid"
} < <(cmd input.txt)

echo success

또는 임시 파일을 사용할 수 있습니다(여기에는 문서가 있고 여기에는 임시 파일을 사용하여 bash에서 구현되었던 문자열이 있습니다).

#! /bin/bash -
set -o nounset -o pipefail -o errexit
tmp=$(mktemp)
{
  rm -f -- "$tmp"
  cat input.txt >&3
  exec 3>&-

  while IFS= read -r line || [ -n "$line" ]; do
    printf '%s\n' "$line" || exit
  done
  wait "$pid"
} 3> "$tmp" < "$tmp"

echo success

이렇게 하면 명령이 실패하고 출력을 메모리에 여러 번 저장하지 않으면 출력이 처리되지 않고 후행 빈 줄이 유지됩니다.

아무튼 꼭 봐주세요쉘 루프를 사용하여 텍스트를 처리하는 것이 왜 나쁜 습관으로 간주됩니까?

답변2

이와 같이:

#!/bin/bash
set -euo pipefail
IFS=$'\n\t'

[[ -s input.txt ]]
while read -r l; do
    echo "${l}"
done <<< "$(cat input.txt)"

echo Success

관련 정보