Ответ 1
В bash команда замены подстановки foo > >(bar)
завершается, как только заканчивается foo
. (Это не обсуждается в документации.) Вы можете проверить это с помощью
: > >(sleep 1; echo a)
Эта команда немедленно возвращается, а затем выводит a
асинхронно через секунду.
В вашем случае команда tee
занимает только один бит времени для завершения после завершения command
. Добавление sync
дало tee
достаточно времени для завершения, но это не устраняет условие гонки, не более, чем добавление sleep
, это просто делает гонку более маловероятной для проявления.
В общем случае sync
не имеет видимого внутри себя эффекта: имеет значение только если вы хотите получить доступ к устройству, где ваши файловые системы хранятся в другом экземпляре операционной системы. В более четких выражениях, если ваша система теряет мощность, после перезагрузки будут доступны только данные, записанные до последнего sync
.
Что касается снятия условия гонки, вот несколько возможных подходов:
-
Явно синхронизировать все замещенные процессы.
mkfifo sync.pipe command > >(tee -- "$stdoutF"; echo >sync.pipe) 2> >(tee -- "$stderrF"; echo >sync.pipe) read line < sync.pipe; read line < sync.pipe
-
Используйте другое временное имя файла для каждой команды вместо повторного использования
$stdoutF
и$stderrF
и убедитесь, что временный файл всегда создан. -
Откажитесь от замены процесса и используйте трубы вместо этого.
{ { command | tee -- "$stdoutF" 1>&3; } 2>&1 \ | tee -- "$stderrF" 1>&2; } 3>&1
Если вам нужен статус возврата команды, bash помещает его в
${PIPESTATUS[0]}
.{ { command | tee -- "$stdoutF" 1>&3; exit ${PIPESTATUS[0]}; } 2>&1 \ | tee -- "$stderrF" 1>&2; } 3>&1 if [ ${PIPESTATUS[0]} -ne 0 ]; then echo command failed; fi