![grep --quiet의 종료 상태에 문제가 있습니까?](https://linux55.com/image/219267/grep%20--quiet%EC%9D%98%20%EC%A2%85%EB%A3%8C%20%EC%83%81%ED%83%9C%EC%97%90%20%EB%AC%B8%EC%A0%9C%EA%B0%80%20%EC%9E%88%EC%8A%B5%EB%8B%88%EA%B9%8C%3F.png)
grep 버전 2.16이 설치된 SLES 12 SP5 시스템이 있고 한 시스템에서는 grep --quiet
다음 조건이 포함된 스크립트를 많이 사용합니다.
# $pid_list contains the result of pstree and $script_pid equals $$
if echo "$pid_list" | grep -qF "($script_pid)"; then
continue
fi
if echo "$pid_list" | grep -qF "($script_pid)"; then
echo "Error: grep has a bug!"
continue
fi
첫 번째 조건이 실패할 확률이 약 0.1%이고 두 번째 동일한 조건이 성공할 확률이 두 배로 증가합니까? !
다음과 같이 조건을 변경하면 완벽하게 작동합니다(전체 코드여기):
if echo "$pid_list" | grep -F "($script_pid)" >/dev/null; then
continue
fi
매뉴얼과 관련하여 이 quiet
옵션은 예상대로 작동해야 합니다. 오류가 발생하면 true를 반환해야 합니다.
일치하는 항목이 발견되면 오류가 감지되더라도 상태 0으로 즉시 종료됩니다.
그래서 가끔 왜 실패하는지 혼란스러워요. 머신의 RAM과 파일 시스템은 모두 정상입니다. grep 바이너리에도 올바른 파일 해시가 있습니다.
나검색 제출, 하지만 내가 찾은 유일한 것은2001년부터, 이는 다음의 일부여야 합니다.2.16 2014년부터.
업데이트 1
@kamil이 제안한 대로 서브셸을 사용해 보았지만 여전히 실패합니다(때때로 "경합 조건" 오류가 표시됨).
if (echo "$pid_list"; true) | grep -qF "($script_pid)"; then
continue
elif (echo "$pid_list"; true) | grep -qF "($script_pid)"; then
echo "Error: Race condition!"
continue
fi
대신 다음과 같이 작동합니다.
if echo "$pid_list" | grep -qF "($script_pid)" || [[ $? -eq 141 ]]; then
continue
fi
답변1
가정: 실행하는 스크립트에서 set -o pipefail
(스크립트를 해석하는 쉘이 Bash인 경우, 다른 쉘도 유사한 기능을 제공할 수 있음). 에서 man 1 bash
:
pipefail
설정된 경우 파이프라인의 반환 값은 0이 아닌 상태로 종료된 마지막(가장 오른쪽) 명령의 값이거나, 파이프라인의 모든 명령이 성공적으로 종료된 경우 0입니다. 이 옵션은 기본적으로 비활성화되어 있습니다.
일치하는 항목이 있으면 grep -q
일찍 종료하고 돌아옵니다 0
. 그 다음에echo
돌아올 수도 있고 안 돌아올 수도 있다141
. 이는 echo
파이프 끝을 닫기 전에 파이프 버퍼에 모든 것을 쓸 수 있는지 여부에 따라 달라집니다. grep
같은 입력이라도 상황은 이런저런 식으로 진행될 수 있습니다.경쟁 조건. 이런 일이 발생 하면 141
파이프의 반환 값 141
은 pipefail
.
실제로 사용한다고 가정하면 set -o pipefail
관찰되는 동작은 확실히 grep
쉘의 결함이 아닙니다. 오류는 스크립트에 있습니다.
연결된 질문에 대한 내 대답은 해결책을 제공합니다. 가장 쉬운 방법은 다음과 같습니다.
if (/bin/echo "$pid_list"; true) | grep -qF "($script_pid)"; then
또는
if ((echo "$pid_list"); true) | grep -qF "($script_pid)"; then
왜 /bin/echo …
아니면 (echo …)
대신 echo
? echo
쉘이 내장되었을 가능성이 높으므로 "그것"이 SIGPIPE를 수신하면 실제로는 SIGPIPE를 수신하고 종료되는 전체 서브쉘입니다 . 우리는 실행되어야 하는 서브쉘이 true
종료되는 것을 원하지 않습니다. 시작 부분 참조이 답변.
전체 스크립트를 확인하세요. 다른 조건도 같은 방식으로 문제를 일으킬 수 있습니다.