프로세스 교체를 통해 동시에 실행 중인 독립 프로세스의 비결정적 출력

프로세스 교체를 통해 동시에 실행 중인 독립 프로세스의 비결정적 출력

존재하다bash v4.1.2(2), 아래의 간단한 설명은 문제를 설명하기 위한 최소한의 예일 뿐이며 겉보기에 무작위 출력을 제공합니다.

$ for n in {0..1000}; do echo "$n"; done | 
  tee >(head -n2) >(sort -grk1,1 | head -n3) >/dev/null

다음은 일관된 출력을 제공합니다.

$ seq 0 10000 | tee >(head -n2) >(sort -grk1,1 | head -n3) >/dev/null

특히, 첫 번째 명령문의 경우 sort명령은 무작위로 연속되는 트리플(예: 226,225,224; 52,51,50; 174,173,172 등)을 선택합니다. 출력의 이질성을 이해하려면 해당 명령을 여러 번 실행한 다음 다양한 가능성을 나열할 수 있습니다.

$ seq -w 0 2000 | while read x; do for n in {0..1000}; do echo "$n"; done | 
  tee >(head -n2) >(sort -grk1,1 | head -n3) >/dev/null | cat > "file_${x}"; done

다양한 출력의 발생 횟수를 계산합니다.

$ for f in file_*; do sort -g "$f" | tail -n3 | paste -sd, ; done  | 
  sort | uniq -c | sort -gk1,1 -k2,2
   1 7,8,9
   1 17,18,19
   1 40,41,42
   1 43,44,45
   1 47,48,49
   1 50,51,52
   1 54,55,56
   1 58,59,60
   1 59,60,61
   1 66,67,68
   1 71,72,73
   1 78,79,80
   1 103,104,105
   1 104,105,106
   1 106,107,108
   1 110,111,112
   1 111,112,113
   1 121,122,123
   1 125,126,127
   1 129,130,131
   1 134,135,136
   1 136,137,138
   1 142,143,144
   1 143,144,145
   1 148,149,150
   1 150,151,152
   1 156,157,158
   1 157,158,159
   1 165,166,167
   1 171,172,173
   1 173,174,175
   1 174,175,176
   1 177,178,179
   1 179,180,181
   1 181,182,183
   1 183,184,185
   1 185,186,187
   1 186,187,188
   1 191,192,193
   1 194,195,196
   1 198,199,200
   1 200,201,202
   1 206,207,208
   1 208,209,210
   1 209,210,211
   1 210,211,212
   1 216,217,218
   1 217,218,219
   1 233,234,235
   1 236,237,238
   1 237,238,239
   1 238,239,240
   1 242,243,244
   1 245,246,247
   1 246,247,248
   1 254,255,256
   1 256,257,258
   1 267,268,269
   1 270,271,272
   1 273,274,275
   1 277,278,279
   1 279,280,281
   1 287,288,289
   1 288,289,290
   1 305,306,307
   1 306,307,308
   1 307,308,309
   1 326,327,328
   1 337,338,339
   1 339,340,341
   1 340,341,342
   1 351,352,353
   1 357,358,359
   1 359,360,361
   1 365,366,367
   1 368,369,370
   1 370,371,372
   1 376,377,378
   1 377,378,379
   1 383,384,385
   1 386,387,388
   1 388,389,390
   1 401,402,403
   1 408,409,410
   1 409,410,411
   1 415,416,417
   1 419,420,421
   1 424,425,426
   1 426,427,428
   1 432,433,434
   1 454,455,456
   1 462,463,464
   1 466,467,468
   1 475,476,477
   1 482,483,484
   1 487,488,489
   1 504,505,506
   1 508,509,510
   1 511,512,513
   1 532,533,534
   1 538,539,540
   1 544,545,546
   1 548,549,550
   1 558,559,560
   1 603,604,605
   1 604,605,606
   1 608,609,610
   1 659,660,661
   1 660,661,662
   1 663,664,665
   1 668,669,670
   1 692,693,694
   1 699,700,701
   1 717,718,719
   1 738,739,740
   1 740,741,742
   1 750,751,752
   1 771,772,773
   1 784,785,786
   1 796,797,798
   1 799,800,801
   1 806,807,808
   1 814,815,816
   1 832,833,834
   1 848,849,850
   1 858,859,860
   1 869,870,871
   1 922,923,924
   1 952,953,954
   1 961,962,963
   1 985,986,987
   2 64,65,66
   2 127,128,129
   2 141,142,143
   2 169,170,171
   2 170,171,172
   2 172,173,174
   2 187,188,189
   2 221,222,223
   2 234,235,236
   2 252,253,254
   2 292,293,294
   2 350,351,352
   2 364,365,366
   2 375,376,377
   2 622,623,624
   2 666,667,668
   3 70,71,72
   3 102,103,104
   3 137,138,139
   3 155,156,157
1826 998,999,1000

결과의 정확도는 약 91%인 것으로 나타났습니다. >(head -n2)명령문에서 프로세스 대체를 생략하면 tee100% 올바른 출력이 생성됩니다. 경쟁 조건이 해석 질문과 관련된 이유를 이해하지 못합니다. 이는 명령문의 각 프로세스로 대체된 출력의 상대적 순서에만 영향을 미치기 때문입니다 tee(즉, >(head -n2)먼저 완료되거나 >(sort -grk1,1 | head -n3)이 작업을 수행할 수 있지만 이는 결과 자체가 아니라 출력 순서입니다. 두 명령의 출력이 무작위로 인터리브되면 이해할 수 있습니다. 루프의 동일한 복사본이 tee각 프로세스에 배포되어야 하고 두 프로세스 교체가 모두 별도의 하위 쉘에서 실행되기 때문입니다(stdoutstdin>()https://unix.stackexchange.com/a/331199/14960), 어느 쪽도 다른 쪽에게 영향을 주어서는 안 되지만 분명히 상호 작용합니다. 상호작용을 해석하는 방법은 무엇입니까? 또한 for/ 루프 while의 출력을 bash여러 독립 프로세스에 어떻게 배포할 수 있습니까 tee?

답변1

head -n2두 줄을 읽은 후 종료됩니다. 그런 다음 tee다음에 파이프에 기록될 때 (SIGPIPE로 인해) 죽고 head, 지금까지 수신된 행을 기준으로 정렬된 자체 파이프의 다른 쪽 끝에서도 죽기 sort때문에 eof를 보게 됩니다 .tee

seq가 아닌 루프에서 이를 보는 이유는 루프가 write()파이프에서 여러 s를 실행하고 tee시간에 따라 tee여러 번의 짧은 읽기가 실행될 수 있기 때문입니다. seq전체 출력이 한 번에 기록되지만 하나만 tee수행됩니다 read(). 이렇게 하면 seq 1000000볼 수 있습니다.무작위의행동도 마찬가지다.

head이 문제를 해결하려면 처음 두 줄을 출력한 후 계속해서 읽는 버전이 필요합니다 . 예를 들어 대신에 또는를 사용할 수 있습니다 sed '3,$d'.head -n2sed 2q

또는 다음을 사용하십시오:

... | (
 trap '' PIPE
 exec tee >(trap - PIPE; exec head -n2) >(trap - PIPE; sort -rn | head -n2)
) > /dev/null

SIGPIPE는 ( tee만) 무시되지만 일부 tee구현 에서는 write()파이프가 실패하기 때문에 일부 오류 메시지가 표시됩니다.

tee: /proc/self/fd/13: I/O error

정렬된 출력은 다음과 같습니다.가능한정렬되지 않은 상태로 따르므로 보장되지 않습니다. 보다 일반적으로, 동시에 실행되는 프로그램을 조정하는 것이 없으면 출력 순서를 실제로 보장할 수 없습니다.

관련 정보