이 스크립트가 최신 파일을 안정적으로 기록하지 못하는 이유는 무엇입니까?

이 스크립트가 최신 파일을 안정적으로 기록하지 못하는 이유는 무엇입니까?

이 스크립트는 때때로 실패하고 때로는 성공합니다(매우 짜증나는 상황).

#!/bin/bash
set -Eeuxo pipefail

test_dir="$(mktemp -d)"
touch "$test_dir/file"{001..312}
latest_file="$(find $test_dir -type f | sort -r | head -n1)"
echo $latest_file

성공하면 다음과 같이 기록됩니다.

++ mktemp -d
+ test_dir=/tmp/tmp.yWelcpBYB7
+ touch /tmp/tmp.yWelcpBYB7/file001 /tmp/tmp.yWelcpBYB7/file002 ... /tmp/tmp.yWelcpBYB7/file312
++ find /tmp/tmp.yWelcpBYB7 -type f
++ head -n1
++ sort -r
+ latest_file=/tmp/tmp.yWelcpBYB7/file312
+ echo /tmp/tmp.yWelcpBYB7/file312
/tmp/tmp.yWelcpBYB7/file312

실패하면 다음과 같이 기록됩니다.

++ mktemp -d
+ test_dir=/tmp/tmp.VzTqmgpZyG
+ touch /tmp/tmp.VzTqmgpZyG/file001 /tmp/tmp.VzTqmgpZyG/file002 ... /tmp/tmp.VzTqmgpZyG/file312
++ find /tmp/tmp.VzTqmgpZyG -type f
++ sort -r
++ head -n1
+ latest_file=/tmp/tmp.VzTqmgpZyG/file312

echo $latest_file라인 은 다음 과 같습니다.~ 아니다xtrace에 나타나더라도 여기서 실행됩니다.

10,000개의 파일을 사용하면 성공적으로 실행될 수 없으므로 이것이 무엇인가 관련이 있는 것으로 의심됩니다.머리멎는찾다일찍.

#!/bin/bash
set -Eeuxo pipefail

test_dir="$(mktemp -d)"
touch "$test_dir/file"{0000..9999}
latest_file="$(find $test_dir -type f | sort -r | head -n1)"
echo $latest_file

오류 발생 시 중지를 억제하는 경우(사용세트 +e), 성공합니다:

#!/bin/bash
set -Eeuxo pipefail

test_dir="$(mktemp -d)"
touch "$test_dir/file"{0000..9999}
set +e
latest_file="$(find $test_dir -type f | sort -r | head -n1)"
set -e
echo $latest_file

이 스크립트가 최신 파일을 안정적으로 기록하지 못하는 이유는 무엇입니까?

답변1

문제는 -e. 왜? -e프로세스가 0이 아닌 종료 코드로 종료되는 경우 bash를 중단합니다(전체 규칙은 좀 더 복잡합니다). 파이프가 있으면 마지막 명령만 계산됩니다.

의 나머지 출력을 무시하려면 head -n1파이프를 끊어야 하기 때문에( 로 확인할 수 있음) 내부적으로 오류 상황이 발생 합니다 .stracesort

따라서 스크립트가 에서 안정적으로 작동하도록 하려면 파이프 끝에 -e를 추가할 수 있습니다 . 여전히 파이프가 끊어지지만 더 이상 파이프의 마지막 명령이 아니기 때문에 에서는 고려되지 않습니다 . 파이프에 대해서는 작동하지 않습니다.cathead-ecat

#!/bin/bash
set -Eeuxo pipefail

test_dir="$(mktemp -d)"
touch "$test_dir/file"{0000..9999}
latest_file="$(find $test_dir -type f | sort -r | head -n1 | cat)"
echo $latest_file

확인해주십시오set -e(또는 set -o errexit 또는 트랩 ERR)가 예상한 대로 수행되지 않는 이유는 무엇입니까?-e왜 그렇게 불안정한 기능인지, 그리고 어떤 종류의 문제가 발생할 수 있는지 알아보세요 . 마지막에는 많은 예가 있습니다. 내가 좋아하는 것:

#!/bin/bash

set -e
foo=$(expr 1 - 1)
echo survived

그럴 것이다~ 아니다인쇄살아남았다, 해당 줄은 실행되지 않습니다. 하지만 가 있었다면 foo=$(expr 2 - 1)echo실행될 것입니다!

자체 오류 검사를 구현하는 것이 더 나을 것입니다. -e최고의 솔루션은 아닙니다.

관련 정보