Bagaimana saya mendeteksi dari dalam skrip shell jika output standarnya dikirim ke terminal atau jika disalurkan ke proses lain?
Contoh kasus: Saya ingin menambahkan kode pelarian untuk mewarnai output, tetapi hanya ketika dijalankan secara interaktif, tetapi tidak ketika disalurkan, mirip dengan apa yang ls --color
dilakukan.
Jawaban:
Dalam shell POSIX murni,
mengembalikan "terminal", karena output dikirim ke terminal Anda, sedangkan
mengembalikan "bukan terminal", karena output dari tanda kurung disalurkan ke
cat
.The
-t
flag dijelaskan dalam halaman manusia sebagai... di mana
fd
dapat menjadi salah satu tugas deskriptor file yang biasa:sumber
-t
flag dispesifikasikan dalam POSIX, dan karenanya harus bekerja untuk semua shell yang kompatibel dengan POSIX (artinya, ini bukan ekstensi bash). pubs.opengroup.org/onlinepubs/009695399/utilities/test.htmlfish
jawaban shell. Menggunakannyatest
rapi, tapi saya tidak bisa mencoba contoh yang diurung karena tidak didukung. Sudah mencoba membungkusnya dengan analogbegin; ...; end
, tetapi itu tampaknya tidak berhasil, dan hanya menjalankan blok kode positif lagi. Pikir saya mungkin perlu menggunakanstatus
tetapi tampaknya tidak memeriksa perpipaan. Saya kira saya pada dasarnya ingin memeriksa apakah STDOUT dari perintah / skrip sebelumnya tidak disetel ke terminal, berkat jawaban klarifikasi ini.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:
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: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 terbarussh
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-TTYssh
sedang digunakan: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:
stat
deskriptor file on / dev / stdin[[ "${-}" =~ 'i' ]]
tty
dantty -s
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.
sumber
stat
panggilan pada / dev / stdin. Dan mengapa"${-}"
atautty -s
tidak bekerja? Saya juga melihat ke dalam kode sumbercat
tetapi gagal melihat bagian mana yang melakukan keajaiban di sana yang tidak dapat Anda lakukan di shell POSIX. Bisakah Anda mengembangkannya?Perintah
test
(builtin inbash
), memiliki opsi untuk memeriksa apakah file descriptor adalah tty.Lihat "
man test
" atau "man bash
" dan cari "-t
"sumber
help test
(danhelp help
untuk lebih banyak), laluinfo bash
untuk informasi yang lebih mendalam. Perintah-perintah ini sangat bagus jika Anda akhirnya membuat skrip offline, atau hanya ingin mendapatkan pemahaman yang lebih luas.Anda tidak menyebutkan shell mana yang Anda gunakan, tetapi di Bash, Anda bisa melakukan ini:
sumber
Tentang Solaris, saran dari Dejay Clayton kebanyakan berhasil. -P tidak merespon seperti yang diinginkan.
bash_redir_test.sh terlihat seperti:
Di Linux, ini bekerja dengan sangat baik:
Tentang Solaris:
sumber
Kode berikut (hanya diuji di linux bash 4.4) tidak boleh dianggap portabel atau direkomendasikan , tetapi demi kelengkapan, ini adalah:
Saya tidak tahu mengapa, tetapi sepertinya file descriptor "3" entah bagaimana dibuat ketika fungsi bash telah STDIN piped.
Semoga ini bisa membantu,
sumber