Como verificar se um shell está logado / interativo / em lote

145

Acho que entendo as diferenças entre um shell interativo, um login e um lote. Consulte os seguintes links para obter mais ajuda:

Minha pergunta é: como posso testar com um comando / condição se estiver em um shell interativo, de login ou de lote?

Estou procurando um comando ou condição (que retorne trueou false) e que também possa ser colocado em uma instrução if. Por exemplo:

if [[ condition ]]
   echo "This is a login shell"
fi
Amelio Vazquez-Reina
fonte
3
Há ainda outra pergunta: STDIN e / ou STDOUT estão conectados a um tty (terminal) ou a um pipe (arquivo ou processo)? Este é um teste relacionado, mas distinto, conforme descrito em alguns dos comentários abaixo.
Mark Hudson

Respostas:

162

Estou assumindo um bashshell, ou similar, já que não há shell listado nas tags.

Para verificar se você está em um shell interativo:

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

Para verificar se você está em um shell de login:

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

Por "lote", presumo que você queira dizer "não interativo", portanto a verificação de um shell interativo deve ser suficiente.

Chris Down
fonte
12
Para os zshusuários, a verificação de um shell de login pode ser feita com:if [[ -o login ]] ...
chb
1
Se você quiser saber se um "usuário" executou seu programa versus "cron". [[TERM == "dumb"]] && echo "Executando em cron.
Erik Aronesty
10
@ErikAronesty Nem todos os terminais burros são sessões cron.
Chris Baixo
2
“Estou assumindo um shell bash, ou similar, já que não há shell listado nas tags.” - A lógica desta afirmação é realmente bonita! :)
Michael Le Barbier Grünewald
2
@antonio Isso ocorre porque sua cotação está errada, $-está sendo expandida no shell atual. Se você usar aspas simples em torno da expressão completa você vai obter o resultado correto:bash -c '[[ $- == *i* ]] && echo "Interactive" || echo "Not interactive"'
Chris Baixo
33

Em qualquer shell no estilo Bourne, a iopção indica se o shell é interativo:

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

Não há uma maneira portátil e totalmente confiável de testar um shell de login. Ksh e zsh adicionam la $-. O Bash define a login_shellopção com a qual você pode consultar shopt -q login_shell. Portably, teste se $0começa com um -: shells normalmente sabem que são shells de logon porque o chamador adicionou um -prefixo ao argumento zero (normalmente o nome ou o caminho do executável). Isso falha ao detectar maneiras específicas de shell de chamar um shell de login (por exemplo ash -l).

Gilles
fonte
(...) porque o chamador - acho que falta algo nesse fragmento.
Piotr Dobrogost
Seria ideal se $0sempre começar com um, -não importa como foi iniciado. Mas há pelo menos uma exceção: isso nem sempre é verdade com o bash, mesmo que seja para ser um shell de logon. Experimente na sua caixa: invoque bash --logine $0continue lendo bash.
Wirawan Purwanto
@WirawanPurwanto Não sei se entendi o seu comentário. Não foi isso que escrevi na minha última frase?
Gilles
@ Gilles: Você está correto. Desculpe, perdi sua última frase.
Wirawan Purwanto
24

casca de peixe

Aqui está a resposta para o fishcaso de outros usuários encontrarem essa página.

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"

Documentação de peixes: inicialização

oh apesar
fonte
1
-1 para editorial desnecessário.
precisa saber é o seguinte
6
Se alguém se pergunta sobre o comentário de @ NickBastin, ele tinha um argumento justo, então eu fiz uma edição. A quantidade original de snarkiness foi cortada pela metade.
ohspite
18

csh / tcsh

Para cshe tcsheu tenho o seguinte no meu .cshrcarquivo:

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

Especificamente para tcsh, a variável loginshé configurada para um shell de logon:

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

( tcshtambém possui uma variável shlvldefinida como o número de shells aninhados, em que o shell de login tem um valor de 1.)

Andrew Stein
fonte
2
PS1não funciona para testar um shell interativo. É quase sempre definido de forma interativa, mas você pode desmarcá-lo. Muitas vezes, é definido em um shell não interativo, porque muitos sistemas são enviados com o export PSin /etc/profile.
Gilles
@Gilles Obrigado pela correção e edição #
Andrew Stein
17

Outra maneira é verificar o resultado de tty

if [ "`tty`" != "not a tty" ]; then
Adrian Cornish
fonte
10
... ou use [ -t 0 ]para testar se STDIN é um tty. Você também pode usar 1 (STDOUT) ou 2 (STDERR), dependendo de suas necessidades.
derobert
@derobert - graças por me mostrar algo novo
Adrian Cornish
10
Este é um teste diferente. É possível ter um shell não interativo cuja entrada seja um terminal (sempre que você executar um script em um terminal!), E é possível (embora raro) ter um shell interativo que receba entradas que não sejam de um terminal.
Gilles
@Gilles se o shell era interativo e fechou deixando uma criança disownviva, ttyfuncionou melhor para saber que não é mais interativo, enquanto $-não mudou; Ainda estou intrigado sobre qual é a melhor abordagem.
Poder de Aquário
5
@AquariusPower Então, o que você deseja testar não é para um shell interativo, mas se a entrada padrão é um terminal. Use [ -t 0 ]. PS No meu comentário anterior, escrevi que “existe uma forte correlação” - eu esqueci “além do caso extremamente comum de um script iniciado com #!/bin/shou similar”, que não é interativo, mas pode ser conectado a um terminal.
Gilles
8

O UNIX / Linux possui um comando para verificar se você está em um terminal.

if tty -s
then
echo Terminal
else
echo Not on a terminal
fi
Paulo
fonte
1
Isso funciona dashtambém.
Ken afiada
7

Você pode verificar se stdin é um terminal:

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

Para verificar se um script é executado em um shell interativo ou não interativo, verifico em meus scripts a presença de um prompt armazenado na $PS1variável:

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

Isso eu aprendi aqui: https://www.tldp.org/LDP/abs/html/intandnonint.html

Christian Herenz
fonte
1

inão é a opção correta para procurar. -ié forçar um shell não interativo a se tornar interativo. A opção correta ativada automaticamente é -s, mas o Bash infelizmente não lida com isso corretamente.

Você precisa verificar se $-contém s(isso é concedido para ser ativado automaticamente) ou se ele contém i(isso não é concedido para ser ativado automaticamente, mas oficialmente acoplado apenas à -iopção de linha de comando do shell).

esperto
fonte
1
sseria se o shell ler comandos do stdin, não se for interativo. Um shell interativo não necessariamente lê comandos do stdin (tente zsh -i < /dev/null, embora o zsh pareça ser a exceção aqui). E um shell pode estar lendo comandos do stdin e não ser interativo (como sh < fileou echo 'echo "$1"' | sh -s foo bar).
Stéphane Chazelas
2
O que eu queria ressaltar é que o Bourne Shell original não possui 'i' em $ -, mesmo quando se pretende que seja interativo.
schily
OK, mas no U&L, "shell" tende a se referir a conchas modernas . O shell Bourne é geralmente considerado um relicário e sua própria variante não é convencional o suficiente para esperar que as pessoas saibam do que você está falando, a menos que seja explícito. A pergunta mencionada [[...]]que implica ksh / bash / zsh. Como observação histórica, você tem um argumento de que o check- iin $-não funcionará no shell Bourne. Mas a verificação stambém não funcionará lá de maneira confiável. Você também deseja procurar por [ -t 0 ]ou i; mesmo assim isso seria enganado em casos de canto comoecho 'exec < /dev/tty; that-check' | sh'
Stéphane Chazelas
Solaris até Solaris 10 vem com o Bourne Shell original e até o peitoril inclui aprox. 10 bugs conhecidos no shell desde o SVr4. Portanto, adicionar uma dica ao Bourne Shell não é tão desonesto quanto você pode acreditar. O zsh, por outro lado, não é compatível o suficiente, por exemplo, falha quando você tenta executar o "configure" com o zsh, portanto, tenha cuidado em configurar / bin / sh para apontar para o zsh. BTW: meu Bourne Shell define -i por padrão, caso decida ser interativo.
schily
3
Percebo que o POSIX parece não exigir $ - contém i (o que parece exigir s), levantarei a questão no ML do grupo austin.
Stéphane Chazelas