Не існує надійного способу визначити, чи STDIN, STDOUT або STDERR переносяться на / з вашого сценарію, в першу чергу через такі програми ssh
.
Речі, які "нормально" працюють
Наприклад, наступне рішення bash працює правильно в інтерактивній оболонці:
[[ -t 1 ]] && \
echo 'STDOUT is attached to TTY'
[[ -p /dev/stdout ]] && \
echo 'STDOUT is attached to a pipe'
[[ ! -t 1 && ! -p /dev/stdout ]] && \
echo 'STDOUT is attached to a redirection'
Але вони не завжди працюють
Однак, виконуючи цю команду як команду не TTY ssh
, потоки STD завжди виглядають так, як вони переносяться. Щоб продемонструвати це, використовуючи STDIN, оскільки це простіше:
# CORRECT: Forced-tty mode correctly reports '1', which represents
# no pipe.
ssh -t localhost '[[ -p /dev/stdin ]]; echo ${?}'
# CORRECT: Issuing a piped command in forced-tty mode correctly
# reports '0', which represents a pipe.
ssh -t localhost 'echo hi | [[ -p /dev/stdin ]]; echo ${?}'
# INCORRECT: Non-tty mode reports '0', which represents a pipe,
# even though one isn't specified here.
ssh -T localhost '[[ -p /dev/stdin ]]; echo ${?}'
Чому це важливо
Це досить велика справа, оскільки це означає, що для скрипту bash немає способу сказати, чи є нетипізована ssh
команда в трубі чи ні. Зауважте, що ця нещасна поведінка була введена, коли останні версії ssh
почали використовувати труби для не TTY STDIO. У попередніх версіях використовувалися сокети, які МОЖЕ бути диференційовані з башти за допомогою використання [[ -S ]]
.
Коли це має значення
Це обмеження зазвичай викликає проблеми, коли ви хочете написати скрипт bash, який має поведінку, схожу на компільовану утиліту, наприклад cat
. Наприклад, cat
дозволяє наступну гнучку поведінку в обробці різних джерел входу одночасно, і досить розумна, щоб визначити, чи приймає він трубопровідний вхід незалежно від того, використовується не-TTY або примусово-TTY ssh
:
ssh -t localhost 'echo piped | cat - <( echo substituted )'
ssh -T localhost 'echo piped | cat - <( echo substituted )'
Ви можете зробити щось подібне лише в тому випадку, якщо зможете достовірно визначити, задіяні труби чи ні. В іншому випадку виконання команди, яка зчитує STDIN, коли вхід не доступний ні з труб, ні з перенаправлення, призведе до того, що сценарій зависне і чекає введення STDIN.
Інші речі, які не працюють
Намагаючись вирішити цю проблему, я розглянув кілька методів, які не вирішили проблему, включаючи такі, які включають:
- вивчення змінних середовища SSH
- за допомогою
stat
дескрипторів файлів on / dev / stdin
- вивчення інтерактивного режиму через
[[ "${-}" =~ 'i' ]]
- вивчення статусу tty через
tty
таtty -s
- вивчення
ssh
статусу через[[ "$(ps -o comm= -p $PPID)" =~ 'sshd' ]]
Зауважте, що якщо ви використовуєте ОС, яка підтримує /proc
віртуальну файлову систему, вам, можливо, пощастить, перейшовши на символічні посилання для STDIO, щоб визначити, використовується труба чи ні. Однак /proc
це не крос-платформене, сумісне з POSIX рішення.
Мені надзвичайно цікаво вирішити цю проблему, тому, будь ласка, повідомте мене, якщо ви думаєте про будь-яку іншу техніку, яка могла б працювати, бажано на POSIX-рішеннях, які працюють як на Linux, так і на BSD.