반복적으로 실행되는 프로그램의 출력을 합산하는 스크립트를 테스트하는 동안 이해할 수 없는 동작을 발견했습니다. 이를 재현하려면 out
내 프로그램의 출력을 나타내는 텍스트 파일을 생성하고 sum
, 이 파일은 이전 실행에서 반환된 값의 합계를 보유하고 의 복사본으로 시작합니다 out
.
cat > out << EOF
2 20
5 50
EOF
cp out sum
달리는 중에 이상한 일이 일어납니다
paste out sum | awk '{$1 += $3; $2 += $4; NF = 2; print}' | tee sum
여러 번(15~20회 소요될 수 있음) 실행할 때마다 명령은 sum
해당 값에 값을 추가 out
하고 결과를 다시 작성해야 합니다 sum
. 내가 얻는 것은 예측할 수 없는 횟수만큼 작동한 sum
다음
2 20
5 50
나중에 배웠어요작업 중인 동일한 파일로 출력을 리디렉션하거나 티잉할 수 없습니다.임시 파일을 사용하면 문제가 해결되었지만 이 동작은 여전히 혼란스럽습니다.
… | tee sum
제한된 횟수의 반복으로도 작동하지만… > sum
덮어쓰지 않는 이유는 무엇입니까sum
?왜 예상대로 작동하지 않습니까?
답변1
이것,
paste out sum | awk ... | tee sum
경쟁 조건이 있습니다. 읽기 위해 paste
열고 , 쓰기 위해 열고, 자릅니다. 쉘은 거의 동시에 시작되므로 파일을 먼저 여는 쉘에 따라 다릅니다.sum
tee
물론 실제로는 쉘이 특정 순서에 따라 한 번에 하나씩 유틸리티를 시작해야 합니다. 왼쪽에서 오른쪽으로 실행될 수도 있으므로 paste
먼저 실행될 가능성이 더 높을 수도 있지만 이는 구현 세부 사항이며 어쨌든 실행할 시기는 OS 스케줄러가 결정합니다.
먼저 진행 하면 paste
데이터가 그대로 유지되고 데이터를 읽을 충분한 시간이 있는 파일이 열립니다. 파일을 읽기 전에 열면 tee
빈 파일이 보입니다.paste
paste
여기,
paste out sum | awk ... > sum
쉘은 sum
쓰기를 위해 열리고 잘립니다. 이는 start 와 병렬로 실행될 수 있지만 paste
잘림에는 sum
다른 유틸리티 시작이 포함되지 않으므로 먼저 발생할 수 있습니다. (리디렉션을 처리하는 규칙과 이와 같은 파이프라인에서 명령이 시작되는 순서가 있는지 확실하지 않지만 이에 의존하지는 않습니다.)
sponge
이 문제를 해결하는 도구가 있습니다 .그것에 관한 질문). 얻은 입력을 수집하고 입력이 닫힌 후에만 씁니다. 이는 sum
항상 올바르게 업데이트되어야 합니다.
paste out sum | awk ... | sponge sum