Есть ли способ прервать команду оболочки piped? - PullRequest
2 голосов
/ 17 января 2020

С помощью этой команды:

$ tar -ztf /tmp/z.txz | grep -m 1 '/packagesite.txz$'
2.2.0/FreeBSD:11:amd64/latest/packagesite.txz

Результат приходит очень быстро (менее 1 секунды), но затем он продолжает работать еще 10-15 бесполезных секунд. Я узнал о -m здесь , но это не помогло. Было бы очень хорошо, если бы я смог прервать его сразу после нахождения совпадения. Там в любом случае? К вашему сведению: /bin/sh.

Ответы [ 4 ]

1 голос
/ 20 января 2020

Пока ничего не опубликовано, но я заметил кое-что интересное в этом сообщении :

find . ... -exec sh -c 'printf "%s\n" "$1"; kill "$PPID"' sh {} \;

и больше информации о конвейеры и группы процессов в этой записи :

Если pid равно 0, то sig отправляется каждому процессу в группе процессов вызывающего процесса.

Итак, я начал играть, и вот, на самом деле, это сработало:

$ time tar -ztf /tmp/z.txz | grep -m1 '/packagesite\.txz$'
2.2.0/FreeBSD:11:amd64/latest/packagesite.txz
53.866 real, 3.947 user, 5.119 sys
$
$ time tar -ztf /tmp/z.txz | ( grep -m1 '/packagesite\.txz$' ; kill 0 )
2.2.0/FreeBSD:11:amd64/latest/packagesite.txz
Terminated
0.008 real, 0.003 user, 0.004 sys

Сначала я волновался из-за выхода текста "Termination", но это не так на стандартный вывод, чтобы он не мешал:

$ tar -ztf /tmp/z.txz | ( grep -m1 '/packagesite\.txz$' ; kill 0 ) > z.out
Terminated
$ cat z.out
2.2.0/FreeBSD:11:amd64/latest/packagesite.txz

РЕДАКТИРОВАТЬ:

Однако я отмечаю, что это решение портит код состояния, Например:

$ tar -ztf /home/mrengert/tmp/z.txz | ( grep -m1 '/packagesite\.txz$' ; kill 0 )
2.2.0/FreeBSD:11:amd64/latest/packagesite.txz
Terminated
$ echo $?
143

Кроме того - если вы используете его в сценарии, вы должны быть осторожны с предотвращением распространения сигнала, в противном случае сценарий будет прерван. Вам нужно сделать что-то вроде этого:

#!/bin/sh
trap '' SIGTERM  # ignore signal temporarily
( trap - SIGTERM ; tar -ztf z.txz | ( grep -m1 '/packagesite\.txz$' ; kill 0 ) )
trap - SIGTERM   # restore signal handling
0 голосов
/ 20 января 2020

Ваша проблема связана с буферизацией. Вот более простой способ воспроизвести.

perl -le 'for (1..1000) { print "$_"; sleep 1 }' | grep -m 1 4

Ничего не происходит, хотя вы можете проверить, убрав grep, что четвертая строка вывода соответствует.

Поворот Отключение буферизации из Perl решает непосредственную проблему:

perl -le '$| = 1; for (1..1000) { print "$_"; sleep 1 }' | grep -m 1 4
4

(и, как и ожидалось, выход приходит через 4 секунды).

Не существует полностью переносимых решений для этого; проверьте, есть ли у вас одна из утилит, описанных в https://mywiki.wooledge.org/BashFAQ/009, или, возможно, убедитесь, что tar выдает достаточно данных, чтобы можно было полагаться на заполнение буфера вывода.

0 голосов
/ 20 января 2020

Возможно, ваш файл большой или устройство хранения медленное. Grep собирается отфильтровать результат и прекратить чтение канала, но не прервет команду piped.

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

timeout 1 tar -ztf /tmp/z.txz | grep -m1 '/packagesite.txz$'
0 голосов
/ 20 января 2020

Да, он не работает должным образом, согласно моим поискам и обращению к grep man страницам, к которым он работает только с файлами.

ниже приведен фрагмент страницы man:

-m NUM, --max-count = NUM ​​

Прекратить чтение файла после NUM совпадений строк. Если ввод является стандартным вводом из обычного файла, и выводятся строки соответствия NUM, grep гарантирует, что стандартный ввод будет расположен сразу после последней совпадающей строки перед выходом, независимо от наличия конечных строк контекста. Это позволяет вызывающему процессу возобновить поиск. Когда grep останавливается после NUM совпадающих строк, он выводит любые завершающие контекстные строки. Когда также используется параметр - c или --count, grep не выводит счетчик больше, чем NUM. Когда также используется опция -v или --invert-match, grep останавливается после вывода NUM несовпадающих строк.

...