여기서 무슨 일이 일어나고 있는지 오해하고 있을 수도 있지만 이것이 파이프 버퍼링과 관련이 있는 것 같습니다. 다양한 로깅 수준을 달성하기 위해 여러 파일 설명자(#3 이상)를 사용하는 스크립트가 있습니다. 명령줄 옵션에 따라 그 중 일부는 동일한 파일로, 일부는 콘솔로, 일부는 /dev/null
. 파일 대신 표준 출력으로 변환합니다. 그 이유는 여러 파일 설명자를 하나의 파일로 리디렉션할 때 순서가 맞지 않게 도착했다는 사실을 알았기 때문입니다. 즉, 나는 기꺼이
exec >/some/file 3>&1
대신에
exec >/some/file 3>/some/file
여태까지는 그런대로 잘됐다. 그러나 때로는 명령의 오류 출력을 가져와서 사용자 정의 설명자 중 하나(예: 3)로 보내야 할 때가 있습니다. 이 설명자는 stdout으로 보내질 수 있습니다(이는 다시 파일로 보내집니다). 그런 다음 순서가 잘못된 메시지를 받습니다. 이 명령의 메시지는 후속 명령의 메시지 뒤에 나타납니다. 이는 소규모 PoC입니다. 내가 뭘 잘못했나요?
#!/bin/bash
check_if_ordered() {
sort -n -k1 -k2 test_out.txt > test_out_sorted.txt
if ! diff test_out.txt test_out_sorted.txt >/dev/null ; then
echo "Oops, messages are NOT in order" >&2
else
echo "Good, messages are in order" >&2
fi
rm test_out.txt test_out_sorted.txt
}
log() {
while read msg; do
echo "$msg"
done
}
foo() {
for i in {1..150} ; do
echo "$1 $i"
done
}
#### This always works OK, but can't use it in my scenario
echo "Redirecting command output to file"
foo "1" > >(log) > test_out.txt
foo "2" > >(log) >> test_out.txt
check_if_ordered
#### This is similar to what I need to do and always fails
echo "Redirecting stdout to file"
exec >test_out.txt
foo "1" > >(log)
foo "2" > >(log)
check_if_ordered
명령 버퍼링을 비활성화할 수 있는 외부 도구를 알고 있지만 이 경우에는 사용할 수 없다는 점을 덧붙여야 합니다(내 스크립트는 최대한 이식 가능해야 하고 다양한 배포판에서 실행되어야 합니다).
답변1
#### This always works OK, but can't use it in my scenario
foo "1" > >(log) > test_out.txt
foo "2" > >(log) >> test_out.txt
다음 리디렉션이 stdout을 파일로 직접 리디렉션하는 것을 재정의하므로 여기서 프로세스 대체는 중복된 것처럼 보입니다. 즉, 첫 번째 것은 와 동일해야 합니다 foo "1" > test_out.txt
.
#### This is similar to what I need to do and always fails
exec >test_out.txt
foo "1" > >(log)
foo "2" > >(log)
여기서 문제는 프로세스 교체가 비동기적으로 실행되고 루프가 while read; do echo
느리기 때문에 두 번째 루프가 시작될 때 첫 번째 루프가 log
여전히 실행 중이며 파이프 버퍼에서 읽는다는 것입니다. 이는 echo foo > >(cat; sleep 1; echo hi)
명령줄에서 비슷한 작업을 수행하는 것과 비슷하며 hi
다음 프롬프트가 표시된 후에 나타납니다. 또한 wait
여기에는 도움이되지 않는 것 같습니다.
log
그런데 왜 처음에 두 개의 사본이 필요한지 잘 모르겠습니다 . 이 일을 하는 사람은 한 사람이 아닙니다.
exec >test_out.txt
exec 9> >(log)
foo "1" >&9
foo "2" >&9
(내 시스템에서는 cat
대신 를 사용하면 더 빠르고 더 큰 덩어리를 읽기 while read; do echo
때문에 문제가 숨겨집니다 cat
. 하지만 그렇다고 해서 문제가 완전히 해결된다는 의미는 아니며 동일한 복사본이 아닌 다른 작업을 수행하고 싶을 수도 있습니다. 밖의 log
.)
명령 버퍼링을 비활성화할 수 있는 외부 도구를 알고 있다는 점을 덧붙여야겠습니다.
그런 뜻이라면 stdbuf -o0
프로세스 내부(C 라이브러리) 버퍼링에만 도움이 될 것입니다. 여기서는 작동하지 않을 것 같습니다. 쉘은 echo
반환하기 전에 실제로 운영 체제에 데이터를 써야 합니다.