Como um script Bash pode saber como foi executado?

Como um script Bash pode saber como foi executado?

Eu tenho um script Bash que estava tentando fazer para me ajudar a executar um comando bastante complexo com pequenas alterações que ele me perguntaria por meio de eco e leitura.

Encontrei soluções para forçá-lo a rodar um terminal para executar o comando, mas não estou interessado nisso. O que eu gostaria que ele fizesse é, se eu espaçar e apenas pressionar Enter no Nautilus (fazendo com que ele seja executado com Run Software), uma notificação aparecerá suavemente dizendo "Por favor, execute isso a partir de um terminal".

Consigo fazer com que o pop-up aconteça - já que conheço o comando - mas não consigo fazer com que o script Bash diga se está sendo executado dentro de um terminal ou não, parece que sempre penso assim. É mesmo possível?

Responder1

De man bashbaixoEXPRESSÕES CONDICIONAIS:

-t fd  
    True if file descriptor fd is open and refers to a terminal.

Supondo que fd 1 seja padrão, if [ -t 1 ]; thendeve funcionar para você. OGuia avançado de script de shellafirmações -tusadas dessa maneira falharão sshe que o teste (usando stdin, não stdout) deve, portanto, ser:

if [[ -t 0 || -p /dev/stdin ]]

-ptesta se um arquivo existe e é um pipe nomeado. No entanto, eu observaria experimentalmente que isso não é verdade para mim: -p /dev/stdinfalha tanto para terminais normais quanto para sessões ssh, enquanto if [ -t 0 ](ou -t 1) funciona em ambos os casos (veja também os comentários de Gilles abaixo sobre problemas nessa seção doGuia avançado de script de shell).


Se o problema principal for um contexto especializado a partir do qual você deseja chamar o script para se comportar de maneira apropriada a esse contexto, você pode evitar todos esses detalhes técnicos e evitar complicações usando um wrapper e uma variável personalizada:

!#/bin/bash

export SPECIAL_CONTEXT=1
/path/to/real/script.sh

Chame isso live_script.shou qualquer outra coisa e clique duas vezes nele. É claro que você poderia realizar a mesma coisa com argumentos de linha de comando, mas um wrapper ainda seria necessário para fazer com que apontar e clicar em um navegador de arquivos GUI funcionasse.

Responder2

Use a variável bash $SHLVL para detectar o nível de aninhamento do shell. Em um script executado 'raw' clicando duas vezes será 1, em um script executado em um terminal será 2.

#!/bin/bash
if (( SHLVL < 2 )) ; then
    echo "Please run this from a terminal."
    read -p "Press <Enter> to close this window"
    exit 1
fi
# rest of script

Nota: $ não é necessário ao testar variáveis ​​numéricas dentro de (( )).

Responder3

Embora a resposta de Cachinhos Dourados provavelmente esteja correta no caso típico, parece que existem casos extremos. No meu caso, meu xserver está configurado para inicializar tty1e nunca sai desse tty. Se o Xorg stdoutfor um TTY, parece que os clientes terão esse TTY vinculado ao seu descritor de arquivo por padrão.

Veja como resolvi meu problema:

#!/bin/bash
isxclient=$( readlink /dev/fd/2 | grep -q 'tty' && [[ -n $DISPLAY ]] ; echo $? )
if [[ ! -t 2  || $isxclient == "0" ]]; then
        notify-send "Script wasn't started from an interactive shell"
else
        echo "Script was started from an interactive shell"
fi

Não testei isso para ver se funciona em uma configuração X mais padrão e também duvido muito que este seja o único caso extremo. Se alguém encontrar uma solução de aplicação mais geral, volte e conte-nos.

Responder4

Outro, usando as opções do bash, defina a variável interna, $-.

De .bashrc,

# If not running interactively, don't do anything
case $- in
    *i*) ;;
    *) return;;
esac

informação relacionada