Cara memeriksa apakah shell masuk / interaktif / batch

145

Saya rasa saya mengerti perbedaan antara interaktif, login dan shell batch. Lihat tautan berikut untuk bantuan lebih lanjut:

Pertanyaan saya adalah, bagaimana saya bisa menguji dengan perintah / kondisi jika saya sedang interaktif, login atau shell batch?

Saya mencari perintah atau ketentuan (yang mengembalikan trueatau false) dan bahwa saya juga bisa menempatkan pada pernyataan if. Sebagai contoh:

if [[ condition ]]
   echo "This is a login shell"
fi
Amelio Vazquez-Reina
sumber
3
Ada pertanyaan lain: Apakah STDIN dan / atau STDOUT terhubung ke tty (terminal) atau pipa (file atau proses)? Ini adalah tes terkait tetapi berbeda seperti yang dijelaskan dalam beberapa komentar di bawah.
Mark Hudson

Jawaban:

162

Saya mengasumsikan bashshell, atau serupa, karena tidak ada shell yang tercantum dalam tag.

Untuk memeriksa apakah Anda berada di shell interaktif:

[[ $- == *i* ]] && echo 'Interactive' || echo 'Not interactive'

Untuk memeriksa apakah Anda berada di shell login:

shopt -q login_shell && echo 'Login shell' || echo 'Not login shell'

Dengan "batch", saya anggap Anda maksud "tidak interaktif", jadi cek untuk shell interaktif sudah cukup.

Chris Down
sumber
12
Untuk zshpengguna, memeriksa shell login dapat dilakukan dengan:if [[ -o login ]] ...
chb
1
Jika Anda ingin tahu apakah "pengguna" menjalankan program Anda versus "cron". [[TERM == "dumb"]] && echo "Berjalan di cron.
Erik Aronesty
10
@ErikAronesty Tidak semua terminal bodoh adalah sesi cron.
Chris Down
2
"Saya mengasumsikan bash shell, atau serupa, karena tidak ada shell yang tercantum dalam tag." - Logika pernyataan ini benar-benar indah! :)
Michael Le Barbier Grünewald
2
@antonio Itu karena kutipan Anda salah, $-sedang diperluas di shell saat ini. Jika Anda menggunakan tanda kutip tunggal di sekitar ekspresi penuh, Anda akan mendapatkan hasil yang benar:bash -c '[[ $- == *i* ]] && echo "Interactive" || echo "Not interactive"'
Chris Down
33

Dalam shell Bourne-style, iopsi menunjukkan apakah shell itu interaktif:

case $- in
  *i*) echo "This shell is interactive";;
  *) echo "This is a script";;
esac

Tidak ada cara portabel dan sepenuhnya dapat diandalkan untuk menguji shell login. Ksh dan zsh menambahkan luntuk $-. Bash menetapkan login_shellopsi, yang bisa Anda query shopt -q login_shell. Mudah-mudahan, tes apakah $0dimulai dengan -: shell biasanya tahu itu shell login karena pemanggil menambahkan -awalan ke argumen nol (biasanya nama atau jalur yang dapat dieksekusi). Ini gagal mendeteksi cara-cara khusus shell dalam menjalankan shell login (mis ash -l.).

Gilles
sumber
(...) karena penelepon - saya pikir ada sesuatu yang hilang dalam fragmen ini.
Piotr Dobrogost
Akan ideal jika $0selalu dimulai dengan -tidak peduli bagaimana itu dimulai. Tapi setidaknya ada satu pengecualian: Ini tidak selalu benar dengan bash bahkan jika itu seharusnya merupakan shell login. Cobalah di kotak Anda: aktifkan bash --login, lalu $0masih baca bash.
Wirawan Purwanto
@ WirawanPurwanto Saya tidak yakin saya mengerti komentar Anda. Bukankah itu yang saya tulis dalam kalimat terakhir saya?
Gilles
@Gilles: Anda benar. Maaf saya melewatkan kalimat terakhir Anda.
Wirawan Purwanto
24

kulit ikan

Inilah jawaban untuk fishseandainya ada pengguna lain yang menemukan halaman ini.

if status --is-interactive
    # ...
end

if status --is-login
    # ...
end

echo "darn, I really wanted to have to use globs or at least a case statement"

Dokumentasi ikan: inisialisasi

ohspite
sumber
1
-1 untuk editorialisasi yang tidak perlu.
Nick Bastin
6
Jika ada yang bertanya-tanya pada komentar @ NickBastin, dia punya poin yang adil jadi saya mengedit. Jumlah asli dari snarkiness kini telah dipotong setengah.
ohspite
18

csh / tcsh

Untuk cshdan tcshsaya memiliki yang berikut dalam .cshrcfile saya :

if($?prompt) then               # Only interactive shells set $prompt
    ...
endif

Khusus untuk tcsh, variabel loginshditetapkan untuk shell login:

if($?loginsh) then              # A login shell..
    ...
endif

( tcshjuga memiliki variabel shlvlyang diatur ke jumlah shell yang bersarang, di mana shell login memiliki nilai 1.)

Andrew Stein
sumber
2
PS1tidak berfungsi untuk menguji shell interaktif. Ini hampir selalu diatur dalam interaktif, tetapi Anda dapat menghapusnya. Ini sangat sering diatur dalam shell noninteractive, karena banyak sistem kapal dengan export PSdi /etc/profile.
Gilles
@Gilles Terima kasih atas koreksi dan sunting
Andrew Stein
17

Cara lain adalah dengan memeriksa hasilnya tty

if [ "`tty`" != "not a tty" ]; then
Adrian Cornish
sumber
10
... atau gunakan [ -t 0 ]untuk menguji apakah STDIN adalah tty. Anda juga dapat menggunakan 1 (STDOUT) atau 2 (STDERR) tergantung kebutuhan Anda.
derobert
@derobert - terima kasih telah menunjukkan kepada saya sesuatu yang baru
Adrian Cornish
10
Ini adalah tes yang berbeda. Dimungkinkan untuk memiliki shell noninteraktif yang inputnya adalah terminal (kapan saja Anda menjalankan skrip di terminal!), Dan dimungkinkan (walaupun jarang) untuk memiliki shell interaktif yang mengambil input bukan dari terminal.
Gilles
@Gilles jika shell itu interaktif, dan ditutup meninggalkan anak disowndan hidup, ttybekerja lebih baik untuk mengetahui bahwa itu tidak interaktif lagi, sementara $-tidak berubah; Saya masih bingung tentang apa pendekatan terbaik.
Aquarius Power
5
@ AquariusPower Lalu apa yang ingin Anda uji bukan untuk shell interaktif, tetapi apakah input standar adalah terminal. Gunakan [ -t 0 ]. PS Dalam komentar saya sebelumnya, saya menulis bahwa "ada korelasi yang kuat" - Saya lupa "selain dari kasus skrip yang sangat umum dimulai dengan #!/bin/shatau sejenisnya", yang non-interaktif tetapi dapat dihubungkan ke terminal.
Gilles
8

UNIX / Linux memiliki perintah untuk memeriksa apakah Anda berada di terminal.

if tty -s
then
echo Terminal
else
echo Not on a terminal
fi
Paul
sumber
1
Ini dashjuga berfungsi .
Ken Sharp
7

Anda dapat memeriksa untuk melihat apakah stdin adalah terminal:

if [ -t 0 ]
then
    echo "Hit enter"
    read ans
fi
Angelo
sumber
3

Untuk memeriksa apakah skrip berjalan dalam shell interaktif atau non-interaktif, saya memeriksa skrip saya untuk mengetahui prompt yang disimpan dalam $PS1variabel:

if [ -z $PS1 ] # no prompt?
### if [ -v PS1 ]   # On Bash 4.2+ ...
then
  # non-interactive
  ...
else
  # interactive
  ...
fi

Ini saya pelajari di sini: https://www.tldp.org/LDP/abs/html/intandnonint.html

Christian Herenz
sumber
1

ibukan pilihan yang tepat untuk dicari. -iadalah untuk memaksa shell yang tidak interaktif untuk menjadi interaktif. Opsi yang diaktifkan secara otomatis adalah -s, tetapi sayangnya Bash tidak menangani ini dengan benar.

Anda perlu memeriksa apakah $-mengandung s(ini diberikan untuk diaktifkan secara otomatis) atau apakah mengandung i(ini tidak diberikan untuk diaktifkan secara otomatis tetapi secara resmi hanya digabungkan ke -iopsi baris perintah shell).

schily
sumber
1
sakan terjadi jika shell membaca perintah dari stdin, bukan apakah itu interaktif. Shell interaktif tidak harus membaca perintah dari stdin (coba zsh -i < /dev/null, meskipun zsh tampaknya menjadi pengecualian di sini). Dan shell mungkin membaca perintah dari stdin dan tidak bersifat interaktif (suka sh < fileatau echo 'echo "$1"' | sh -s foo bar).
Stéphane Chazelas
2
Yang ingin saya tunjukkan adalah bahwa Bourne Shell asli tidak memiliki 'i' dalam $ -, bahkan ketika itu dimaksudkan untuk menjadi interaktif.
schily
OK, tetapi pada U&L, "shell" cenderung merujuk ke shell modern . Shell Bourne umumnya dianggap relique dan varian Anda sendiri tidak cukup umum untuk membuat orang tahu apa yang Anda bicarakan kecuali Anda membuatnya eksplisit. Pertanyaan yang disebutkan [[...]]yang menyiratkan ksh / bash / zsh. Anda mendapat poin sebagai catatan sejarah bahwa memeriksa imasuk $-tidak akan berfungsi di shell Bourne. Tapi kemudian memeriksa stidak akan bekerja dengan baik di sana. Anda juga ingin memeriksa [ -t 0 ]atau i; bahkan itu akan tertipu dalam kasus sudut sepertiecho 'exec < /dev/tty; that-check' | sh'
Stéphane Chazelas
Solaris hingga Solaris 10 hadir dengan Bourne Shell asli dan bahkan ambang termasuk aprox. 10 bug diketahui berada di shell sejak SVr4. Jadi menambahkan petunjuk pada Shell Bourne bukanlah topi yang licik karena Anda mungkin percaya. zsh di sisi lain tidak cukup kompatibel, misalnya gagal ketika Anda mencoba menjalankan "configure" dengan zsh, jadi berhati-hatilah untuk mengatur / bin / sh untuk menunjuk ke zsh. BTW: Bourne Shell saya menetapkan -i secara default jika itu memutuskan untuk menjadi interaktif.
schily
3
Saya perhatikan POSIX tampaknya tidak memerlukan $ - berisi i (yang tampaknya membutuhkan s), saya akan mengajukan pertanyaan pada austin-grup ML.
Stéphane Chazelas