Tidak ada cara mudah untuk menentukan apakah STDIN, STDOUT, atau STDERR sedang disalurkan ke / dari skrip Anda, terutama karena program seperti ssh
.
Hal-hal yang "normal" bekerja
Misalnya, solusi bash berikut berfungsi dengan benar di shell interaktif:
[[ -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'
Tetapi mereka tidak selalu berhasil
Namun, ketika mengeksekusi perintah ini sebagai perintah non-TTY ssh
, aliran STD selalu terlihat seperti sedang disalurkan. Untuk menunjukkan ini, gunakan STDIN karena lebih mudah:
# 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 ${?}'
Mengapa itu penting?
Ini adalah masalah yang cukup besar, karena ini menyiratkan bahwa tidak ada cara untuk skrip bash untuk mengetahui apakah perintah non-tty ssh
sedang disalurkan atau tidak. Perhatikan bahwa perilaku malang ini diperkenalkan ketika versi terbaru ssh
mulai menggunakan pipa untuk STDIO non-TTY. Versi sebelumnya menggunakan soket, yang BISA dibedakan dari dalam bash dengan menggunakan [[ -S ]]
.
Ketika itu penting
Batasan ini biasanya menyebabkan masalah ketika Anda ingin menulis skrip bash yang memiliki perilaku mirip dengan utilitas yang dikompilasi, seperti cat
. Misalnya, cat
memungkinkan perilaku fleksibel berikut dalam menangani berbagai sumber input secara bersamaan, dan cukup pintar untuk menentukan apakah itu menerima input yang disalurkan terlepas dari apakah non-TTY atau terpaksa-TTY ssh
sedang digunakan:
ssh -t localhost 'echo piped | cat - <( echo substituted )'
ssh -T localhost 'echo piped | cat - <( echo substituted )'
Anda hanya dapat melakukan sesuatu seperti itu jika Anda dapat menentukan dengan andal apakah pipa terlibat atau tidak. Jika tidak, mengeksekusi perintah yang membaca STDIN ketika tidak ada input yang tersedia dari pipa atau pengalihan akan menghasilkan skrip tergantung dan menunggu input STDIN.
Hal-hal lain yang tidak berhasil
Dalam mencoba menyelesaikan masalah ini, saya telah melihat beberapa teknik yang gagal untuk menyelesaikan masalah, termasuk yang melibatkan:
- memeriksa variabel lingkungan SSH
- menggunakan
stat
deskriptor file on / dev / stdin
- memeriksa mode interaktif via
[[ "${-}" =~ 'i' ]]
- memeriksa status tty melalui
tty
dantty -s
- memeriksa
ssh
status melalui[[ "$(ps -o comm= -p $PPID)" =~ 'sshd' ]]
Perhatikan bahwa jika Anda menggunakan OS yang mendukung /proc
sistem file virtual, Anda mungkin beruntung mengikuti tautan simbolik untuk STDIO untuk menentukan apakah pipa digunakan atau tidak. Namun, /proc
bukan solusi lintas platform, kompatibel POSIX.
Saya sangat menarik dalam menyelesaikan masalah ini, jadi tolong beri tahu saya jika Anda memikirkan teknik lain yang mungkin berhasil, lebih disukai solusi berbasis POSIX yang bekerja pada Linux dan BSD.