перенаправление вывода дескриптор файла


Мне нужно иметь возможность перенаправить вывод в файл, а также проверить код возврата скрипта в KSH (не могу использовать pipestatus или pipefail), я нашел решение, но я не уверен, что значение file discriptor 4, может кто-нибудь объяснить, пожалуйста?

{
rc=$(
{
  {
    . somescript.sh 2>&1
    echo "$?" >&3
  } | tee -a somefile.txt
} 3>&1 >&4 4>&-
)
} 4>&1

echo "${rc}"
2 2

2 ответа:

rc=$(...) означает, что код возврата будет тем, что напечатано на файловом дескрипторе (fd) 1 кодом внутри (...). Итак, каким-то образом то, что somescript.sh выводит, должно быть перемещено из fd 1 и затем возвращено позже. Строка echo выводит код возврата somescript.sh в fd 3. Затем 3>&1 отправляет сохраненный код возврата в fd 1, где $(...) ожидает его. Однако это означает, что старому fd 1 (от {somescript 2>&1 } | tee) некуда идти. Таким образом, старый fd 1 перенаправляется на fd 4 С >&4 (и входная сторона закрывается с помощью 4>&-, так как она не будет использоваться). Затем, как только $(...) заканчивается, 4>&1 в конце помещает выходные данные somescript|tee обратно в fd 1, где другие программы ожидают его.

Фу!

Без >&4 Выход somescript.sh и выход echo "$?" были бы смешаны на fd 1 из-за 3>&1. Таким образом, fd 4 является удерживающим пером для фактического вывода somescript.sh в течение того времени, когда fd 1 используется для переноса кода возврата.

Если вы хотите использовать именованный канал, вы можете обойтись без всех пререканий с файловыми дескрипторами:

mkfifo p
tee -a somefile.txt < p &
. somescript.sh > p
rc=$?

Здесь мы запускаем tee в фоновом режиме, позволяя ему считывать входные данные из именованного канала p. После запуска этого задания мы создаем исходный код сценария и перенаправляем его выходные данные в именованный канал. После завершения работы скрипта его состояние выхода можно сохранить в rc с помощью обычного оператора присваивания. Это также закроет конец оболочки трубы, что приведет к тому, что другой конец закроется как ну и позвольте tee выйти.