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

Другие вопросы по тегам