Потратив довольно много времени вчера, пытаясь перенаправить stdout
на stdin
, я остановился на следующем методе. Это не очень хорошо, но я думаю, что я предпочитаю это по названному решению pipe / fifo.
read | { P0 | ... | P(n-1); } >/dev/fd/0
{ ... } >/dev/fd/0
- перенаправить стандартный вывод на стандартный ввод для всей последовательности каналов (т. Е. Он перенаправляет вывод P (n-1) на вход P0). Использование >&0
или чего-то подобного не работает; Вероятно, это связано с тем, что bash предполагает, что 0
доступен только для чтения, в то время как он не против записи в /dev/fd/0
.
Начальный read
-pipe необходим, потому что без него дескриптор файла ввода и вывода является одним и тем же устройством pts (по крайней мере, в моей системе), и перенаправление не имеет никакого эффекта. (Устройство pts не работает как канал; запись в него выводит информацию на экран.) Делая ввод { ... }
нормальным каналом, перенаправление дает желаемый эффект.
Для иллюстрации на моем примере calc
/ square
:
function calc() {
# calculate sum of squares of numbers 0,..,10
sum=0
for ((i=0; i<10; i++)); do
echo $i # "request" the square of i
read ii # read the square of i
echo "got $ii" >&2 # debug message
let sum=$sum+$ii
done
echo "sum $sum" >&2 # output result to stderr
}
function square() {
# square numbers
read j # receive first "request"
while [ "$j" != "" ]; do
let jj=$j*$j
echo "square($j) = $jj" >&2 # debug message
echo $jj # send square
read j # receive next "request"
done
}
read | { calc | square; } >/dev/fd/0
Запуск приведенного выше кода дает следующий вывод:
square(0) = 0
got 0
square(1) = 1
got 1
square(2) = 4
got 4
square(3) = 9
got 9
square(4) = 16
got 16
square(5) = 25
got 25
square(6) = 36
got 36
square(7) = 49
got 49
square(8) = 64
got 64
square(9) = 81
got 81
sum 285
Конечно, этот метод довольно хакерский. В частности, деталь read
имеет нежелательный побочный эффект: завершение «реальной» петли трубы не приводит к прекращению целостности. Я не мог придумать ничего лучше, чем read
, так как кажется, что вы можете определить только, что конвейер завершился, попытавшись записать что-то в него.