Почему трубопроводы и перенаправление работают с документами?

Сочетание переадресации с документом здесь кажется достаточно логичным:

$ bash > foo <<EOF echo Hello EOF $ less foo Hello 

Но с трубой она ведет себя по-другому:

 $ bash | tee foo <<EOF echo Hello EOF $ less foo echo Hello 

Что также странно, если вы сразу вводите «историю»:

 $ bash | tee foo <<EOF echo Hello EOF $ history $ history 1 ... 

То есть первая команда по-прежнему находится внутри вновь созданного bash. Что происходит? Почему труба ведет себя по-другому?

  • Объединение двух сценариев bash путем добавления флагов
  • сохранить дубликаты из $ PATH на источнике
  • Найти команды / функцию, имя которой соответствует значению
  • Определить строку с символами *, одинарной кавычкой и $
  • Развернуть переменную среды из PIPE (SHELL)
  • Сколько снарядов я глубоко?
  • Что делает «set -» в этой точке входа в Dockerfile?
  • Как удалить строку на основе Delimeter в perl / Shell?
  • One Solution collect form web for “Почему трубопроводы и перенаправление работают с документами?”

    Вы перенаправляете входной сигнал tee , а не bash . Использование:

     bash << EOF | tee foo echo Hello EOF 

    Еще несколько примеров, иллюстрирующих, как это работает:

     bash << EO1 3<< EO\2 | tee 3<< EO3 foo 4<< EO4 fed (as a deleted temp file open in read-only mode) to bash fd 0 EO1 fed to bash fd 3 without $variable and $(cmd) expansion EO2 fed to tee fd 3 (not that tee does anything with its fd 3) EO3 fed to tee fd 4 (see how, like any redirection operator 3<< END can appear anywhere on the command line (for simple commands at least)) EO4 

    Перенаправление составных команд:

     { head -n2; wc -l; } << EOF fed as fd 0 for the whole command group $(ps -e) EOF 

    Или:

     if head -n1; then head -n2 fi << EOF 1 2 3 EOF 

    Вы можете использовать один и тот же конечный токен:

     $ ls -l /proc/self/fd << E 3<< E >&2 | 3<< E 4<< E ls -l /proc/self/fd pipe heredoc> E pipe heredoc> E pipe heredoc> E pipe heredoc> E total 0 lr-x------ 1 stephane stephane 64 Feb 24 12:50 0 -> /tmp/zshLiVzp3 (deleted) lrwx------ 1 stephane stephane 64 Feb 24 12:50 1 -> /dev/pts/5 lrwx------ 1 stephane stephane 64 Feb 24 12:50 2 -> /dev/pts/5 lr-x------ 1 stephane stephane 64 Feb 24 12:50 3 -> /tmp/zshFLbQ7T (deleted) lr-x------ 1 stephane stephane 64 Feb 24 12:50 4 -> /proc/25749/fd/ total 0 lr-x------ 1 stephane stephane 64 Feb 24 12:50 0 -> pipe:[70735808] lrwx------ 1 stephane stephane 64 Feb 24 12:50 1 -> /dev/pts/5 lrwx------ 1 stephane stephane 64 Feb 24 12:50 2 -> /dev/pts/5 lr-x------ 1 stephane stephane 64 Feb 24 12:50 3 -> /tmp/zshL3KBp3 (deleted) lr-x------ 1 stephane stephane 64 Feb 24 12:50 4 -> /tmp/zshcJjS7T (deleted) lr-x------ 1 stephane stephane 64 Feb 24 12:50 5 -> /proc/25748/fd/ 

    Что касается того, почему первая команда history запускается в этом новом bash в:

     $ bash | tee foo <<EOF echo Hello EOF $ history $ history 1 ... 

    Это потому, что bash stdin все еще является терминалом, но его stdout – мертвая труба (на другом конце трубы tee перенаправил свой stdin из этого файла temp удаления, так что конец считывания этого канала закрыт).

    bash не пишет свое приглашение или эхо того, что вы набираете на его stdout (мертвая труба), а на терминал, так что bash позволит вам вводить history в первом приглашении.

    Однако эта history (которая является встроенной, так исполняемой процессом bash , а не дочерним), будет записывать свой вывод в этот мертвый канал. При этом процесс bash получит сигнал SIGPIPE (поскольку нет читателя) и умрет.

    Следующее приглашение выдается вызывающей оболочкой.

    Linux и Unix - лучшая ОС в мире.