find [...] -exec
utilizará la ruta (relativa )a los archivos encontrados. Si desea usar -exec
con la suposición de que el archivo encontrado está en el directorio actual, en su lugar desea usar -execdir
.
И Bash, и zsh имеют сопроцессы (, к сожалению, немного разные ), которые, по сути, оборачивают вызов pipe
и порождают подпроцесс с доступными как стандартным вводом, так и стандартным выводом. к вызывающей оболочке. По сути, они позволяют оболочке воспроизводить как x
, так и y
в x | cmd | y
, но при этом все x
, y
и cmd
выполняются из текущего процесса, а , а не в среда выполнения конвейера.
Это позволит нам запустить module 2>&...
для некоторого ...
, при этом module
будет работать из текущей оболочки. Если мы используем cat
в качестве нашего сопроцесса (, то есть cmd
), он просто повторит все снова, а затем мы сможем снова прочитать вывод в текущую оболочку с помощью y <&...
позже.
Другой вариант — перенаправить стандартную ошибку в другой фоновый процесс и wait
для его кода возврата. Я обращусь к обоим ниже.
Я собираюсь использовать эту фальшивую module
функцию для тестирования, чтобы я мог включать и выключать ошибки по своему желанию. If изменяет текущую среду оболочки, чтобы мы могли ее видеть, и выводит «err» в stderr; Я буду комментировать эту строку по мере необходимости:
module() {
sleep 1
FOO=$(date)
echo err >&2
}
Если я запускаю сопроцесс cat
в Bash, я могу перенаправить module
stderr на него и читать из cat
stdout, чтобы делать все, что захочу:
coproc cat
module 2>&${COPROC[1]}
exec {COPROC[1]}>&-
if grep -q err <&${COPROC[0]}
then
echo got an error
else
echo no error
fi
В zsh должно быть
module 2>&p
exec 4<&p
coproc :
if grep -q err <&4
вместо этого посередине.
В любом случае я могу запустить команду module
в текущей оболочке и прочитать вывод об ошибке.Функция может возвращаться в пределах if
как обычно.
Все, кроме cat
, выполняется из текущей среды выполнения. :Перенаправления FD не создают независимые среды, как это делают конвейеры. Мы можем echo $FOO
в конце проверить это и увидеть, что дата обновилась, потому что module
работал в текущей среде.
В качестве альтернативы, фоновый процесс может выполнять всю работу. Это работает в Bash:
exec 2> >( if grep -q. ; then exit 7 ; else exit 0 ; fi )
PID=$!
module
exec 2>&-
wait $PID
echo $?
Приведенное выше выведет либо 7
, либо 0
в зависимости от того, что сказал подпроцесс вверху — вы можете настроить, чтобы делать с кодом возврата все, что вам нравится. В zsh это не так, потому что $!
не установлен для замены процессов; это должно быть решаемо, но я перестал пытаться. Здесь также подойдет фиксированный fifo, а не временный файл.
В этом случае вы, вероятно, захотите сохранить и восстановить FD 2 на любой стороне.
Я не знаю, как работают «Модули среды», но я предполагаю из вашего описания, что это функции оболочки, которые устанавливают переменные среды, и их вывод stderr должен перехватываться/сопоставляться без запуска их в отдельном обработать.
Ответ, нравится вам это или нет, заключается в том, что единственный надежный и очевидный способ — перенаправить их stderr во временный файл. Использование именованных каналов столь же громоздко (, что вам все равно придется создавать временный файл! ), кроме того, что это намного сложнее. А использование co -процессов обременительно, неудобно и непереносимо .
Вbash
(и только в bash
)вы можете воспользоваться преимуществами недокументированной функции ($!
, устанавливаемой на PID из >(...)
подстановки процесса )и выйти сухим из воды. как:
module 2> >(grep error)
wait $! && echo failed
В этом примере предполагается, что module
сам по себе не порождает дочерних элементов, которые могут запутать $!
.
В Linux, как с bash, так и с zsh, вы сможете сделать:
my_module() {
chmod u+w /dev/fd/3 # only needed in bash 5+
module 2> /dev/fd/3 3>&-
! grep -q err /dev/fd/3
} 3<<< ''
3<<< ''
— это здесь -строка, первоначально содержащая пустую строку. И zsh
, и bash
реализуют здесь -строки, а здесь -документы в виде удаленных временных файлов. В Linux (и Cygwin, но, как правило, не в других системах ), открытие /dev/fd/3
открывает файл, на который указывает fd 3, даже если он уже удален (в других системах, он дублирует fd 3 )так что это очень чистый способ работы с временными файлами. Файл уже удален, вам не нужно беспокоиться о его очистке, и он виден на ФС только очень короткое время (начиная с версии 5, однако bash
удаляет права на запись в него, которые нам нужны для работы. вокруг сchmod
).
Здесь вам нужен временный файл, если вы собираетесь запускать module
и grep
последовательно (, а не параллельно в отдельных процессах ). Выполнение этого с каналами (, как в подходах Майкла, но в отличие от @mosvy ), приведет к мертвым -блокировкам, если будет достаточно выходных данных, чтобы заполнить каналы.