Какому потоку Bash пишет свое приглашение?

Я пытаюсь перенаправить все выходные данные из bash (запрос, ввод пользователя, результаты) в файл

Пример:

/bin/bash > file.txt 2>&1 

Я думал, что это сработает, но я не получаю подсказки. Может ли кто-нибудь сказать мне, что я делаю неправильно?

Bash выводит приглашение только в интерактивном режиме. Т.е. он обычно выводится на терминал (/ dev / tty on linux). Это не / dev / stdout или / dev / stdin 🙂

Теперь я не уверен, но могу себе представить, что bash позволит ограничить интерактивный режим, когда нет полностью функционального tty. В этом случае я ожидаю, что приглашение будет записано в stdout. Я не проверял это.

Хорошее доказательство концепции:

 (for a in some set of words; do echo $a > /dev/tty; done) 2>&1 > /dev/null 

будет просто выводить 1,10, как если бы не было перенаправления. Как и приглашение, вывод напрямую отправляется на терминал (который не будет работать, если его нет)

СОВЕТ: если вы хотите, чтобы все было собрано, посмотрите

  • script (1) с scriptreplay ( Захват журналов выполнения в SSH-клиенте или воспроизведение записи оболочки Scripts – это, как представляется, является частью FAQ)
  • переменная PROMPT_COMMAND, которая должна позволить вам печатать материал в stdout в качестве побочного эффекта отображения подсказки
  • set -o xtrace (aka set -x , bash -x т. д.) для общего ведения операторов

Чтобы обмануть bash в мысли, что он находится в интерактивном режиме (хотя stdout не отправляется на терминал), вы можете использовать уже упомянутую команду script .

 ( exec 1> >(tee bashlog.txt) 2>&1 script -q /dev/null /bin/bash -l ) # alternative without script command ( # bash: no job control in this shell exec 1> >(tee bashlog.txt) 2>&1 /bin/bash -il ) 

Приглашение написано на stderr, поскольку ферма (на Solaris здесь) показывает:

 $ truss -ft write -p 10501 10501: write(2, " d", 1) = 1 10501: write(2, " a", 1) = 1 10501: write(2, " t", 1) = 1 10501: write(2, " e", 1) = 1 10501: write(2, "\n", 1) = 1 10521: write(1, " S aturday , S e".., 46) = 46 10501: Received signal #18, SIGCLD [caught] 10501: siginfo: SIGCLD CLD_EXITED pid=10521 status=0x0000 10501: write(2, " $ ", 2) = 2 

Самый простой способ сделать это

 bash -i >/tmp/logfile 2>&1 

Bash будет записывать все в /tmp/logfile и продолжать выполнять команды по мере их ввода, но ничего не будет отображаться в терминале. Вы можете выйти из него, как только вы выйдете из сеанса терминала – нажав Ctrl + D или введите exit .

Обратите внимание, что если вы запускаете одно и то же без перенаправления stderr , у вас будет только приветственное сообщение, записанное в файл, все остальное будет работать в вашем текущем терминале. Таким образом, ответ на ваш вопрос о потоке, к которому bash выводит свою подсказку (и все следующие команды), выглядит следующим образом: stderr .

О да, и параметр -i просто заставляет bash работать в интерактивном режиме. Не слушайте этих людей – вам не нужны волшебные трюки, чтобы сделать это;)