STDOUT & tee /dev/null >(wc -l > tmp.txt)에 대한 삼중 파이핑 및 `cat tmp.txt`를 포함하기 위한 다시 파이핑의 이상한 결과

STDOUT & tee /dev/null >(wc -l > tmp.txt)에 대한 삼중 파이핑 및 `cat tmp.txt`를 포함하기 위한 다시 파이핑의 이상한 결과
$ seq 1 12773 | tee /dev/null >(wc -l > tmp.txt) | head -$((0x`openssl rand -hex 7` % `cat tmp.txt` + 1))|tail -1

--> 8473 (임의로 1~12773 사이)

$ cat tmp.txt

--> 8473

$ seq 1 12774 | tee /dev/null >(wc -l > tmp.txt) | head -$((0x`openssl rand -hex 7` % `cat tmp.txt` + 1))|tail -1

-->(비어 있음)

$ cat tmp.txt

--> 8844 (임의로 1~12773 사이)

$ seq 1 25011 | tee /dev/null >(wc -l > tmp.txt) | cat | head -$((0x`openssl rand -hex 7` % `cat tmp.txt` + 1))|tail -1

--> 13778 (임의로 1~25011 사이)

$ cat tmp.txt

--> 13778

$ seq 1 25012 | tee /dev/null >(wc -l > tmp.txt) | cat |head -$((0x`openssl rand -hex 7` % `cat tmp.txt` + 1))|tail -1

-->(비어 있음)

$ cat tmp.txt

--> 24939 (1~25012 사이에서 임의로)

$ seq 1 46014 | tee /dev/null >(wc -l > tmp.txt) | cat | cat |head -$((0x`openssl rand -hex 7` % `cat tmp.txt` + 1))|tail -1

--> 34111 (임의로 1~46014 사이)

$ cat tmp.txt

--> 34111 (임의로 1~46014 사이)

$ seq 1 46015 | tee /dev/null >(wc -l > tmp.txt) | cat | cat |head -$((0x`openssl rand -hex 7` % `cat tmp.txt` + 1))|tail -1

-->(비어 있음)

$ cat tmp.txt

--> 343 (임의로 1~46014 사이)

cat 뒤의 '|'(wc -l > tmp.txt)' 개수가 늘어날수록 위 명령이 처리하는 라인 수를 늘릴 수 있습니다.

어떻게 되어가나요?

답변1

~처럼알렉스 P이미 댓글에서 설명했지만,파이프라인의 명령은 병렬로 실행됩니다.. 당신은 이것이 사실이 아니라고 확신하는 것 같습니다. 마음을 열지 않는 한 무슨 일이 일어나고 있는지 이해할 수 없다는 오해를 잊어버리십시오.

프로세스가 병렬로 실행되기 때문에 작업 순서는 정확한 시간에 따라 달라지며 한 실행에서 다음 실행으로 복제되지 않을 수 있습니다.

첫 번째 예에서는 다음 명령이 병렬로 실행됩니다.

  • seq 1 12773
  • tee /dev/null
  • wc -l > tmp.txt(프로세스 교체도 파이프를 생성하고 명령을 병렬로 실행합니다)
  • head -$((0x`openssl rand -hex 7` % `cat tmp.txt` + 1))— 여기에는 세 가지 다른 명령이 포함되며 두 head명령이 openssl모두 종료된 cat후에 시작됩니다 .
  • tail -1

병렬로 실행되므로 wc -l > tmp.txt다음 출력 과 관련된 런타임은 예측할 수 없습니다 .cat tmp.txtcat tmp.txtwc

  • 리디렉션을 수행하기 전에 실행될 수 tmp.txt있으며 이전 실행에서 파일을 가져오거나(있는 경우) 파일이 존재하지 않는다고 불평할 수 있습니다.
  • 리디렉션이 수행된 후 실행할 수 있지만 wc이 경우 리디렉션으로 인해 파일이 잘리기 때문에 출력이 생성되기 전에 파일이 비어 있습니다.
  • 출력이 생성되는 동안 실행될 수 wc있으며 출력의 시작 부분만 선택합니다. 대부분의 시스템에서는 wc출력이 자동으로 생성되므로(짧기 때문에) 이런 일이 발생하지 않습니다.
  • wc출력이 완료된 후 실행할 수 있습니다.

실험을 통해 나는 당신과 동일한 결과를 얻었습니다(대부분 유휴 상태였던 커널 3.16을 실행하는 Linux 시스템에서). , 의 출력을 seq 1 12773얻으려면 ; , 를 사용하여 빈 파일을 선택하세요. 그렇다면 12773과 12774 사이에 차이가 있는 이유는 무엇입니까? 그런데 그 아래 결과는 상당히 신뢰할 수 있습니까?cat tmp.txtwcseq 1 12774cat tmp.txt

$ seq 1 12774 | wc -c
65538

임계값은 65536바이트이고 값은 다음과 같습니다.파이프 버퍼 용량. 이 명령은 먼저 실행 하고 완료 head …해야 하므로 시작 속도가 느립니다 . 시작되면 파이프의 이전 명령이 파이프 버퍼에 기록됩니다. 파이프 버퍼가 가득 차면 이전 명령을 중지해야 합니다. 숫자가 12773에 도달하면 파이프 버퍼가 절대 채워지지 않으므로 실행이 이전에 완료되어 (해야 할 작업이 훨씬 적었음) 출력을 작성할 시간이 있었을 가능성이 높습니다. 그러나 숫자가 12774보다 크면 파이프 버퍼가 가득 차서 에 출력 쓰기가 중단되고 아직 출력 쓰기가 완료되지 않았습니다 . 또한 빈 파일로 실행하십시오.opensslcatseqopensslwcteehead …wccat

tee더 많은 파이프를 추가하면 각 파이프에는 자체 버퍼가 있으므로 지연되기 전에 더 많은 공간이 있습니다.

관련 정보