Bir kabuğun login / interaktif / toplu olup olmadığını kontrol etme


143

İnteraktif, giriş ve toplu iş kabuğu arasındaki farkları anladığımı düşünüyorum. Daha fazla yardım için aşağıdaki bağlantılara bakın:

Sorum şu ki, eğer etkileşimli, oturum açmış veya toplu bir kabuğumdaysam nasıl bir komut / koşulla test edebilirim?

Bir komut veya koşul arıyorum (döndüren trueveya döndürür false) ve ayrıca bir if ifadesine de yerleştirebilirim. Örneğin:

if [[ condition ]]
   echo "This is a login shell"
fi

3
Başka bir soru daha var: STDIN ve / veya STDOUT bir tty (terminal) veya bir boruya (dosya veya işlem) bağlı mı? Bu, aşağıdaki yorumların bazılarında açıklandığı gibi ilgili ancak farklı bir testtir.
Mark Hudson,

Yanıtlar:


160

bashEtiketlerde bir kabuk olmadığı için bir kabuk veya benzerini farz ediyorum .

Etkileşimli bir kabukta olup olmadığınızı kontrol etmek için:

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

Giriş kabuğu olup olmadığını kontrol etmek için:

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

"Toplu iş" derken, "etkileşimli değil" demek istediğinizi varsayalım, bu nedenle etkileşimli bir kabuğun kontrolü yeterli olacaktır.


12
İçin zsh: kullanıcılar, bir giriş kabuğu kontrol ile yapılabilirif [[ -o login ]] ...
KHB

1
Bir "kullanıcı" nın programınızı "cron" a karşı çalıştırıp çalıştırmadığını bilmek istiyorsanız. [[TERM == "aptal"]] & & echo "
Cronda koşmak

10
@ErikAronesty Tüm aptal terminaller cron oturumları değildir.
Chris Down,

2
“Etiketlerde listelenen bir kabuk olmadığı için bir bash kabuğu veya benzeri bir varsayım var.” - Bu ifadenin mantığı gerçekten çok güzel! :)
Michael Le Barbier Grünewald

2
@ antonio Bu, teklifinizin yanlış $-olması nedeniyle mevcut kabukta genişletiliyor. Tüm ifadenin etrafında tek tırnak kullanırsanız doğru sonucu alırsınız:bash -c '[[ $- == *i* ]] && echo "Interactive" || echo "Not interactive"'
Chris Down

33

Herhangi bir Bourne tarzı kabuğunda, iseçenek kabuğun etkileşimli olup olmadığını gösterir:

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

Bir giriş kabuğu test etmek için taşınabilir ve tamamen güvenilir bir yol yoktur. Ksh ve zsh eklemek liçin $-. Bash login_shell, sorgulayabileceğiniz seçeneği ayarlar shopt -q login_shell. Taşınabilir olarak, $0a -: ile başlayan olup olmadığını test edin, normalde giriş kabukları olduğunu bilirler; çünkü arayan -sıfır bağımsız değişkenine bir önek ekler (normalde çalıştırılabilir dosyanın adı veya yolu). Bu, bir giriş kabuğu çağırmak için kabuğa özgü yolları saptamaz (örn. ash -l).


(...) çünkü arayan - Bu kısımda eksik olan bir şey olduğunu düşünüyorum.
Piotr Dobrogost

Nasıl $0başladığı -önemli değil, her zaman başlarsa ideal olur . Ancak en az bir istisna vardır: Bu, bir giriş kabuğu olması gerekse bile bash ile her zaman doğru değildir . Kutunuzda deneyin: invoke bash --login, sonra $0hala okur bash.
Wirawan Purwanto

@WirawanPurwanto Yorumunuzu anladığımdan emin değilim. Son cümleme yazdığım şey bu değil miydi?
Gilles,

@Gilles: Haklısın. Üzgünüm son cümlenizi özledim.
Wirawan Purwanto

24

balık kabuğu

İşte fishbu sayfada diğer kullanıcıların yanması ihtimaline karşı cevap .

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"

Balık dokümantasyonu: başlatma


1
Gereksiz editoryalizasyon için -1.
Nick Bastin

6
Birisi @ NickBastin’in yorumunda merak ediyorsa, onun için makul bir nokta vardı, ben de bir düzenleme yaptım. Orijinal miktar keskinliği şimdi yarı yarıya azaldı.
ohspite

18

csh / tcsh

Dosyamda aşağıdakiler var cshve tcshben .cshrc:

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

Özel olarak tcsh, değişken loginshbir giriş kabuğu için ayarlanır:

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

( tcshayrıca shlvlgiriş kabuğunun 1 değerine sahip olduğu, iç içe geçmiş kabuk sayısına ayarlanmış bir değişkeni de vardır .)


2
PS1etkileşimli bir kabuk için test etmek için çalışmaz. Neredeyse her zaman etkileşimli olarak ayarlanır, ancak onu kaldırabilirsiniz. Çoğu sistem etkileşimli olmayan bir kabuk içine yerleştirilir, çünkü birçok sistem export PSiçinde gelir /etc/profile.
Gilles,

@Gilles Düzeltme ve düzenleme için teşekkür ederiz
Andrew Stein

17

Başka bir yolun sonucunu kontrol etmektir tty

if [ "`tty`" != "not a tty" ]; then

10
... veya [ -t 0 ]STDIN'in bir tty olup olmadığını test etmek için kullanın . Gereksinimlerinize bağlı olarak 1 (STDOUT) veya 2 (STDERR) de kullanabilirsiniz.
derobert,

@derobert - bana yeni bir şey gösterdiğin için teşekkürler
Adrian Cornish

10
Bu farklı bir test. Girişi bir terminal olan (herhangi bir zaman bir terminalde bir komut dosyası çalıştırdığınızda!) Etkileşimli olmayan bir kabuğa sahip olmak mümkündür ve bir terminalden değil girişi alan etkileşimli bir kabuğa sahip olmak (nadir de olsa) mümkündür.
Gilles,

@ Kabuk etkileşimliyse ve bir çocuğu disownve canlı bırakarak kapandıysa tty, $-değişmediyse , artık etkileşimli olmadığını bilmek en iyisini yaptı; En iyi yaklaşımın ne olduğu konusunda hala şaşkınım.
Kova Gücü

5
@AquariusPower O zaman test etmek istediğiniz şey etkileşimli bir kabuk için değil, standart girişin bir terminal olup olmadığıdır. Kullanın [ -t 0 ]. PS Önceki yorumumda, “güçlü bir korelasyon var” yazmıştım - #!/bin/shetkileşimli olmayan ancak bir terminale bağlanabilen “ ile ya da benzerleriyle başlayan son derece yaygın bir senaryo örneğini” unuttum .
Gilles

8

UNIX / Linux, terminalde olup olmadığınızı kontrol etme komutuna sahiptir.

if tty -s
then
echo Terminal
else
echo Not on a terminal
fi

1
Bu da işe yarıyor dash.
Ken Sharp,

7

Stdin'in bir terminal olup olmadığını kontrol edebilirsiniz:

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

3

Bir betiğin etkileşimli veya etkileşimli olmayan bir kabukta çalışıp çalışmadığını kontrol etmek için, $PS1değişkende depolanan bir istemin var olup olmadığını kontrol edin :

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

Bunu burada öğrendim: https://www.tldp.org/LDP/abs/html/intandnonint.html


1

iaramak için doğru seçenek değil. -iaksi halde etkileşimli olmayan bir kabuğu etkileşimli olmaya zorlamaktır. Doğru otomatik etkin seçeneği -s, ancak Bash ne yazık ki bu doğru işlemez.

Sen olmadığını kontrol etmek gerekir $-içeren sveya içerdiği olsun (bu otomatik aktive olması verilir) i(bu otomatik aktive ancak resmi sadece bağlanacak şekilde verilmediği -ikabuğun komut satırı seçeneği).


1
sEğer kabuk etkileşimli olup olmadığını değil, stdin komutlarını okursa olur. Etkileşimli bir kabuk mutlaka stdin komutlarını okumaz (deneyin zsh -i < /dev/null, zsh buradaki istisna gibi görünüyor). Ve bir kabuk stdin'den komutları okuyor olabilir ve etkileşimli olamaz ( sh < fileya da gibi echo 'echo "$1"' | sh -s foo bar).
Stéphane Chazelas

2
İşaret etmek istediğim, orijinal Bourne Shell'in etkileşimli olması amaçlandığında bile $ 'da' i'ye sahip olmadığı.
schily

Tamam, ancak U&L'de "kabuk" modern kabuklara gönderme eğilimindedir . Bourne kabuğunun genellikle bir dayanak olduğu düşünülür ve kendi varyantınız, açık bir şekilde ifade etmediğiniz sürece insanların neden bahsettiğinizi bilmesini bekleyecek kadar yaygın değildir. Bu soru [[...]]ksh / bash / zsh anlamına gelir. Bir şekilde bir noktaya değindin tarih notu kontrol o iin $-Bourne kabuğunda çalışmaz. Ama sonra kontrol etmek de sgüvenilir bir şekilde orada çalışmaz. Ayrıca kontrol etmek isterdim [ -t 0 ]ya i; o zaman bile bu köşe davalarında kandırılıyorecho 'exec < /dev/tty; that-check' | sh'
Stéphane Chazelas 18:15

Solaris 10'a kadar Solaris, orijinal Bourne Shell ile birlikte gelir ve hatta eşiği aprox içerir. SVr4'ten beri kabukta olduğu bilinen 10 böcek. Yani Bourne Kabuğuna bir ipucu eklemek, inanabileceğiniz gibi, hararetle şapka değildir. diğer taraftaki zsh uyumlu değil, örneğin zsh ile "configure" kullanmaya çalıştığınızda hata veriyor, bu yüzden /sh / sh 'ı zsh' ye yönlendirecek şekilde ayarlamaya dikkat edin. BTW: Bourne Shell'im etkileşimli olmaya karar vermesi durumunda varsayılan olarak -i ayarlar.
schily

3
POSIX'in $ gerektirdiğini görünmüyor - içerir (i gerektiriyor), austin grubu ML'deki soruyu soracağım.
Stéphane Chazelas
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.