Как определить из сценария оболочки, отправляется ли его стандартный вывод на терминал или он передается другому процессу?
Показательный пример: я хотел бы добавить escape-коды для раскрашивания вывода, но только при интерактивном запуске, а не при передаче по конвейеру, аналогично тому, что ls --color
происходит
Ответы:
В чистой оболочке POSIX,
возвращает «терминал», потому что вывод отправляется на ваш терминал, тогда как
возвращает "не терминал", потому что вывод скобок передается по каналу
cat
.-t
Флаг описан в человеко - страницах , как... где
fd
может быть одно из обычных назначений файловых дескрипторов:источник
-t
флаг указан в POSIX и, следовательно, должен работать для любой POSIX-совместимой оболочки (то есть это не расширение bash). pubs.opengroup.org/onlinepubs/009695399/utilities/test.htmlfish
снарядный ответ. Использованиеtest
аккуратно, но я не могу попробовать пример в скобках, так как это не поддерживается. Попытался обернуть его аналогичным образомbegin; ...; end
, но это, похоже, не сработало, и просто снова запустил блок положительного кода. Думаю, мне, возможно, придется использовать,status
но это, похоже, не проверяет трубопровод. Я предполагаю, что по сути хочу проверить, не установлен ли STDOUT предыдущей команды / сценария на терминал, благодаря этим уточняющим ответам.Не существует надежного способа определить, передаются ли STDIN, STDOUT или STDERR в / из вашего сценария, в основном из-за таких программ, как
ssh
.Вещи, которые "нормально" работают
Например, следующее решение bash правильно работает в интерактивной оболочке:
Но они не всегда работают
Однако при выполнении этой команды как команды, отличной от TTY
ssh
, потоки STD всегда выглядят так, как будто они передаются по конвейеру. Чтобы продемонстрировать это, используйте STDIN, потому что это проще:Почему это важно
Это довольно большое дело, потому что это означает, что сценарий bash не может определить, передается ли не-tty
ssh
команда или нет. Обратите внимание, что это неудачное поведение было введено, когда последние версииssh
начали использовать каналы для не-TTY STDIO. В предыдущих версиях использовались сокеты, которые МОГУТ различать изнутри bash с помощью[[ -S ]]
.Когда это важно
Это ограничение обычно вызывает проблемы, когда вы хотите написать bash-скрипт, который ведет себя как скомпилированная утилита, например
cat
. Например,cat
допускает следующее гибкое поведение при одновременной обработке различных источников ввода и достаточно умен, чтобы определить, получает ли он ввод по каналу независимо от того, используется ли не TTY или принудительный TTYssh
:Вы можете сделать что-то подобное, только если сможете достоверно определить, задействованы ли трубы или нет. В противном случае выполнение команды, которая читает STDIN, когда нет данных, доступных из каналов или перенаправления, приведет к зависанию скрипта и ожиданию ввода STDIN.
Другие вещи, которые не работают
Пытаясь решить эту проблему, я рассмотрел несколько методов, которые не смогли решить проблему, в том числе:
stat
файловых дескрипторов on / dev / stdin[[ "${-}" =~ 'i' ]]
tty
иtty -s
ssh
статуса через[[ "$(ps -o comm= -p $PPID)" =~ 'sshd' ]]
Обратите внимание, что если вы используете ОС, которая поддерживает
/proc
виртуальную файловую систему, вам, возможно, повезет, перейдя по символическим ссылкам для STDIO, чтобы определить, используется ли канал или нет. Однако/proc
это не кроссплатформенное POSIX-совместимое решение.Я чрезвычайно заинтересован в решении этой проблемы, поэтому, пожалуйста, дайте мне знать, если вы думаете о любой другой технике, которая может работать, предпочтительно решениях на основе POSIX, которые работают как на Linux, так и на BSD.
источник
stat
вызова на / dev / stdin. А почему"${-}"
илиtty -s
не работает? Я также изучил исходный код,cat
но не смог понять, какая часть делает магию, которую вы не можете сделать в оболочке POSIX. Не могли бы вы рассказать об этом более детально?Команда
test
(встроеннаяbash
) имеет возможность проверить, является ли дескриптор файла tty.Смотрите "
man test
" или "man bash
" и ищите "-t
"источник
help test
(иhelp help
для получения дополнительной информации), а затемinfo bash
для получения более подробной информации. Эти команды хороши, если вы когда-нибудь заканчиваете писать сценарии в автономном режиме или просто хотите получить более широкое понимание.Вы не упоминаете, какую оболочку вы используете, но в Bash вы можете сделать это:
источник
На Солярисе предложение от Деджея Клейтона работает в основном. -P не отвечает как требуется.
bash_redir_test.sh выглядит так:
В Linux это прекрасно работает:
На Солярисе:
источник
Следующий код (протестированный только в linux bash 4.4) не следует рассматривать как переносимый и не рекомендуемый , но для полноты здесь он таков:
Я не знаю почему, но кажется, что файловый дескриптор "3" каким-то образом создается, когда функция bash имеет канал STDIN.
Надеюсь, поможет,
источник