2010-03-16 2 views
25

Я пишу скрипт оболочки POSIX, который может или не может принимать входные данные из stdin (как в foo.sh < test.txt, не интерактивно). Как проверить, есть ли что-нибудь на stdin, чтобы не останавливаться на while read -r line...?Обнаружить наличие содержимого stdin в сценарии оболочки

+0

stdout: http://stackoverflow.com/questions/911168/how-to-detect-if-my-shell-script-is-running-through-a-pipe –

ответ

39

Если я получаю правильный вопрос, вы можете попробовать следующее:

#!/bin/sh 
if [ -t 0 ]; then 
    echo running interactivelly 
else 
    while read -r line ; do 
     echo $line 
    done 
fi 
+0

Просто голова, это срабатывает для stdin и когда вы записываете stdout. (оба работают interactivelly) ./yourscript <./the_input_your_giving_your_script.txt && ./yourscript> ./what_your_script_outputs.txt – DebugXYZ

+1

@DeShawnWilliams Нет, ответ @ dmedvinsky верен: 'test -tn' истинно, если дескриптор файла' n' открыт на терминале, поэтому 'test -t 0' проверяет только stdin и' test -t 1 'проверяет только stdout. – bootleg

1

Если вы никогда не хотите запускать сценарий в интерактивном режиме, сделайте его входным файлом в качестве параметра, вместо использования stdin. Некоторые программы используют флаг или специальное имя файла, чтобы указать, что они должны принимать входные данные от стандартного ввода, а не из файла; этот случай позволяет обрабатывать командную строку, если необходимо.

Если вы хотите, чтобы ваш сценарий принимал стандартный ввод, почему бы вам не позволить ему быть интерактивным (или, по крайней мере, вести себя как другие инструменты POSIX)?

+4

Обычный способ сказать программам читать из stdin вместо файла должен содержать '-' вместо имени файла. – Cascabel

6

Вы можете легко реализовать подобное поведение как команды «кошки», которая считывается из списка предоставленных файлов или если они 'не предоставляется, затем читайте с stdin.

Хотя вы не можете использовать эту идею, я думаю, что эта статья Linux Journal будет интересен для вас http://www.linuxjournal.com/content/determine-if-shell-input-coming-terminal-or-pipe

:-)

+0

Ummm, ответ от d.m. это круто^_^ – darkturo

+0

Эта ссылка была очень полезной, спасибо! – hamstar

8

Чтобы ответить на этот вопрос буквально (а не то, что вы на самом деле хотите): read -t 0

Таймаут, ноль секунд.

  1. это состояние гонки, в зависимости от того, когда левая сторона готова предоставить данные. Вы можете указать -t 5, но и на систему обмолота, даже это проблематично.
  2. read -t не стандартизирован в SUSv3. Это в BSD sh, bash, zsh. Это не в ksh или тире.

Таким образом, вы не можете просто использовать #!/Bin/sh и рассчитывать на это.

Основная проблема заключается в том, что даже если в настоящее время нет ничего на stdin, это не значит, что скоро не будет. Вызов программы обычно оставляет stdin подключенным к терминалу/что угодно, поэтому нет возможности рассказать, что нужно.

Таким образом, чтобы ответить на ваш вопрос буквально, вы можете сделать это, но на практике ваши варианты:

  1. тест, если STDIN является терминал: [ -t 0 ]
  2. использование ARGV для управления поведением
+1

Я просто экспериментировал с этим с помощью zsh. Я заметил, что 'read -t' или эквивалентно' read -t0' имеют ** недетерминированное ** поведение. Как вы уже упоминали, не используйте его. – Tarrasch

+1

Но это следует отличать от _test_ '-t', используемого в ответе. –

Смежные вопросы