Как проверить состояние выхода левой команды в трубе «влево | Право «в приборной панели, когда левая команда дает большой выход

paste -d",''," ./file1 - ./file2 - - </dev/null >out

... учитывая данные вашего примера, которые записываются в вывод:

'1','1','1,2',
'2','2','1,3',
'3','3','1,4',
'4','4','1,5',
'5','5','1,6',
'6','6','1,7',
'7','7','1,8',
'8','8','1,9',
'9','9','1,10',
'10','10','2,1',
,'2,3',
,'2,4',
,'2,5',
,'2,6',
,'2,7',
,'2,8',
,'2,9',
,'',

Мне немного сложно точно сказать, каковы критерии для остановки вывода, но записать вывод, идентичный выводу вашего примера:

{   paste -d",''," ./file1 - ./file2 - - |
    sed -ne's/,/&/4p;t' -eq
}   </dev/null

'1','1','1,2',
'2','2','1,3',
'3','3','1,4',
'4','4','1,5',
'5','5','1,6',
'6','6','1,7',
'7','7','1,8',
'8','8','1,9',
'9','9','1,10',
'10','10','2,1',
1
02.10.2018, 00:43
2 ответа

Вы можете использовать именованный канал и соединить два процесса вручную. Запускайте их в обратном порядке, чтобы левая сторона -работала на переднем плане, и вы получали статус выхода из $?, как обычно.

#!/bin/sh
dir=$(mktemp -d)
mkfifo "$dir/p"
cat < "$dir/p" > /dev/null &
( echo foo; exit 12; ) > "$dir/p"
echo "exit status: left: $?"
rm -r "$dir"

Или, если вы хотите и то, и другое, получите PID фонового процесса из $!и wait, чтобы получить статус выхода.

#!/bin/sh
dir=$(mktemp -d)
mkfifo "$dir/p"
( echo foo; exit 12; ) > "$dir/p" &          # left-hand side
pidleft=$!
( cat; exit 34; ) < "$dir/p" > /dev/null &   # right-hand side
pidright=$!
wait "$pidleft"; exitleft=$?
wait "$pidright"; exitright=$?
echo "exit status: left: $exitleft right: $exitright"
rm -r "$dir"

Можно еще оставить вторую часть трубы на переднем плане, я просто хотел сделать это симметрично.


Вы также можете, например,. сохранить статус выхода в файлы и получить их оттуда:

#/bin/sh
( somecmd; echo "$?" > exit1 ) | ( cat; echo "$?" > exit2)
echo "exit status: left: $(cat exit1) right: $(cat exit2)"

Я не думаю, что именованный канал будет здесь полезен, поскольку статус выхода занимает всего пару байтов. Оболочка будет ждать завершения конвейера, прежде чем пытаться прочитать exit1и exit2во второй строке.

Если вместо этого вы хотите использовать именованные каналы, вам необходимо перевести конвейер в фоновый режим, поскольку запись в каналы блокируется до тех пор, пока не будет открыта сторона чтения.

#/bin/sh
mkfifo exit1 exit2
( somecmd; echo "$?" > exit1 ) | ( cat; echo "$?" > exit2) &
echo "exit status: left: $(cat exit1) right: $(cat exit2)"

Однако, если cats читает каналы по какой-то причине, подоболочки, пишущие в них, будут блокироваться на неопределенный срок в фоновом режиме.

1
27.01.2020, 23:31

Вы можете отключить свой скрипт, закрыв стандартный вывод в левой части конвейера и стандартный ввод справа сразу после выхода из фактических команд:

Пример:

#! /bin/dash
rm -f /tmp/s1 /tmp/s2
mkfifo /tmp/s1 /tmp/s2
{ (echo yes; exit 13); s1=$?; exec >&-; echo $s1 >/tmp/s1 & } | { (cat; exit 17); s2=$?; exec <&-; echo $s2 >/tmp/s2 & }
echo "`cat /tmp/s1` `cat /tmp/s2`"

Замените (...; exit..)соответствующими командами.

Закрытие стандартного входа в правой части канала после выхода фактической команды вызывает запись ()в левой части для получения SIGPIPE или EPIPE вместо блокировки при попытке передать команду echo... >fifo &из правый (, который сам заблокирован в открытом ()), и закрытие стандартного вывода слева вызывает чтение ()в правой части канала для получения EOF вместо попытки передать канал из блокирующего echo... >fifo &слева.

Спасибо @ilkkachu за исправление.

1
27.01.2020, 23:31

Теги

Похожие вопросы