Странные результаты тройного трубопровода в STDOUT & tee / dev / null> (wc -l> tmp.txt) & piping снова внедряют `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 

-> (NULL)

 $ 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 

-> (NULL)

 $ 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 

-> (NULL)

 $ cat tmp.txt 

-> 343 (случайный от 1 до 46014)

Как число '| cat's behind "(wc -l> tmp.txt)", вы можете заставить вышеуказанные команды работать с большим количеством строк.

Что происходит?

Как объяснил AlexP в комментариях, команды в конвейере работают параллельно . Вы, кажется, убеждены, что это не так; пожалуйста, забудьте об этом заблуждении, вы не сможете понять, что происходит, пока вы не открываете свой разум.

Поскольку процессы выполняются параллельно, последовательность операций зависит от точного времени и может не воспроизводиться с одного запуска на другой.

Взяв первый пример, следующие команды запускаются параллельно:

  • 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.txt выполняются параллельно, это непредсказуемо, когда cat tmp.txt будет запущен относительно вывода из wc :

  • Он может запускаться до того, как выполняется перенаправление на tmp.txt , и либо забрать файл из предыдущего прогона, если он есть, либо пожаловаться на то, что файл не существует в противном случае.
  • Он может запускаться после выполнения перенаправления, но до того, как wc какой-либо вывод; в этом случае файл пуст, так как перенаправление обрезает файл.
  • Он может работать, пока wc производит выход, и выбирает только начало вывода. В большинстве систем wc производит свой вывод атомарно (потому что он настолько короткий), так что этого не произойдет.
  • Он может работать после того, как wc закончит выпуск продукции.

Экспериментально, я получаю те же результаты, что и вы (на машине Linux, работающей под управлением ядра 3.16, которая в большинстве случаев просто не работает): с seq 1 12773 cat tmp.txt подбирает выход wc ; с seq 1 12774 , cat tmp.txt берет пустой файл. Итак, почему существует разница между 12773 и 12774, но результаты довольно надежны ниже этого значения?

 $ seq 1 12774 | wc -c 65538 

Существует порог в 65536 байт, и это значение является пропускной способностью буфера . Команда « head … запускается медленно, потому что она сначала запускает openssl и cat . Пока он запускается, предыдущая команда в конвейере записывает в буфер потока. Когда буфер буфера заполняется, предыдущая команда должна останавливаться. С номерами до 12773 буфер буфера никогда не заполняется, поэтому, по всей вероятности, seq заканчивает работу перед openssl (у него гораздо меньше работы), и wc имеет время, чтобы написать свой вывод. Но с номерами больше 12774 буфер буфера заполняется; поэтому tee застревает на выходе, который идет в head … и не заканчивает запись вывода на wc . Тем временем cat работает с пустым файлом.

Когда вы добавляете больше каналов, у каждого есть свой собственный буфер, поэтому перед tee стоит больше места.