ksh: как зондировать stdin?
Я хочу, чтобы мой скрипт ksh имел различное поведение в зависимости от того, поступает ли что-то через stdin или нет:
(1) cat file.txt | ./script.ksh (then do "cat <&0 >./tmp.dat" and process tmp.dat)
vs. (2) ./script.ksh (then process $1 which must be a readable regular file)
Проверка stdin на наличие терминала [ -t 0 ] бесполезна, потому что мой скрипт вызывается из другого скрипта.
Выполнение команды "cat <& 0>./ tmp.dat" для проверки размера tmp.dat зависает в ожидании EOF от stdin, если stdin "пустой" (2-й случай).
Как просто проверить, пусто ли stdin или нет?!
3 ответа
РЕДАКТИРОВАТЬ: вы работаете на HP-UX
проверенный [ -t 0 ]
на HP-UX, и это, кажется, работает для меня. Я использовал следующую настройку:
/tmp/x.ksh:
#!/bin/ksh
/tmp/y.ksh
/tmp/y.ksh:
#!/bin/ksh
test -t 0 && echo "terminal!"
Бег /tmp/x.ksh
печатает: terminal!
Не могли бы вы подтвердить вышеизложенное на своей платформе и / или предоставить альтернативную настройку теста, более точно отражающую вашу ситуацию? Ваш сценарий в конечном итоге порожден cron
?
РЕДАКТИРОВАТЬ 2
Если отчаянно, и если Perl доступен, определите:
stdin_ready() {
TIMEOUT=$1; shift
perl -e '
my $rin = "";
vec($rin,fileno(STDIN),1) = 1;
select($rout=$rin, undef, undef, '$TIMEOUT') < 1 && exit 1;
'
}
stdin_ready 1 || 'stdin not ready in 1 second, assuming terminal'
РЕДАКТИРОВАТЬ 3
Обратите внимание, что время ожидания может быть значительным, если ваш вклад поступает от sort
, ssh
и т. д. (все эти программы могут порождать и устанавливать канал с вашим сценарием за секунды или минуты, прежде чем создавать какие-либо данные поверх него.) Кроме того, использование значительного тайм-аута может значительно наказать ваш сценарий, когда на входе нет ничего для начала (например, терминал).)
Если потенциально большие тайм-ауты являются проблемой, и если вы можете повлиять на то, как вызывается ваш скрипт, вы можете заставить вызывающих абонентов явно указывать вашей программе, следует ли использовать stdin, с помощью пользовательской опции или в стандартном GNU
или же tar
(например, script [options [-]] FILE ..., где FILE может быть именем файла, -
для обозначения стандартного ввода или их комбинации, и ваш сценарий будет читать только со стандартного ввода, если -
были переданы в качестве параметра.)
Эта стратегия работает для bash и, вероятно, будет работать для ksh. Опрос 'tty':
#!/bin/bash
set -a
if [ "$( tty )" == 'not a tty' ]
then
STDIN_DATA_PRESENT=1
else
STDIN_DATA_PRESENT=0
fi
if [ ${STDIN_DATA_PRESENT} -eq 1 ]
then
echo "Input was found."
else
echo "Input was not found."
fi
Почему бы не решить эту проблему более традиционным способом и использовать аргумент командной строки, чтобы указать, что данные будут поступать из stdin?
Для примера рассмотрим разницу между:
echo foo | cat -
а также
echo foo > /tmp/test.txt
cat /tmp/test.txt