Come può uno script Bash dire come è stato eseguito?


10

Ho uno script Bash che stavo cercando di aiutarmi a eseguire un comando piuttosto complesso con piccole modifiche che mi avrebbe chiesto attraverso l'eco e la lettura.

Ho trovato soluzioni per costringerlo a eseguire un terminale per eseguire il comando, ma non mi interessa. Quello che mi piacerebbe fare è che, se mi stacco e premo Enter su di esso in Nautilus (facendolo funzionare con Run Software), si aprirà delicatamente una notifica che dice "Esegui questo da un terminale".

Riesco a far apparire il popup - come in conosco il comando - ma non riesco a dire allo script Bash se viene eseguito all'interno di un terminale o meno, sembra sempre pensarlo. È anche possibile?

Risposte:


10

Da man bashsotto ESPRESSIONI CONDIZIONATE :

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

Supponendo che fd 1 sia standard, if [ -t 1 ]; thendovrebbe funzionare per te. La Guida agli script della shell avanzata afferma che in -tquesto modo verrà eseguito il failover sshe che il test (utilizzando stdin, non stdout) dovrebbe quindi essere:

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

-pverifica se esiste un file ed è una pipe denominata. Tuttavia , noterei dal punto di vista esperienziale questo non è vero per me: -p /dev/stdinfallisce sia per i normali terminali sia per le sessioni ssh, mentre if [ -t 0 ](o -t 1) funziona in entrambi i casi (vedere anche i commenti di Gilles di seguito sui problemi in quella sezione della Guida di scripting Shell avanzata ).


Se il problema principale è un contesto specializzato dal quale si desidera chiamare lo script per comportarsi in modo appropriato per quel contesto, è possibile eludere tutti questi aspetti tecnici e salvare se stessi usando un wrapper e una variabile personalizzata:

!#/bin/bash

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

Chiama questo live_script.sho qualsiasi altra cosa e fai doppio clic su quello invece. Ovviamente potresti realizzare la stessa cosa con gli argomenti della riga di comando, ma sarebbe comunque necessario un wrapper per far funzionare il point and click in un browser di file GUI.


5
questa è la risposta corretta - è anche il modo in cui POSIX dice che una shell dovrebbe rilevare se è interattiva o no.
Mikeserv,

2
@DanielAmaya: se si reindirizza l'input, lo script non viene eseguito su un terminale. La domanda è come rilevare se lo script viene eseguito su un terminale.
Mikeserv,

2
Sei sicuro dell'uso di ||dentro [ … ]così? Se lo usi, [[ … ]]allora andrebbe bene, ma normalmente ||viene utilizzato per separare i comandi ed [ -t 0è una chiamata errata [perché ]manca l'ultimo . Di solito non c'è nemmeno un comando -p. Sono d'accordo con i test per un terminale; questo è probabilmente il modo di farlo. È solo la sintassi di cui mi preoccupo.
Jonathan Leffler,

1
@JonathanLeffler Right; ciò dovrebbe produrre un errore di sintassi, poiché l'operatore shell ||viene visualizzato prima ]dell'argomento finale richiesto [.
Chepner,

3
Quella sezione della Guida avanzata agli script di Bash contiene diversi errori. PS1non è un test affidabile per stabilire se la shell è interattiva. "Se uno script ha bisogno di verificare se è in esecuzione in una shell interattiva" è anche fonte di confusione: dovrebbe essere se un codice deve essere testato - di solito uno script non è in esecuzione in una shell interattiva (ma può esserlo, se è di provenienza) . Il test per iin $-è il modo corretto per verificare se la shell è interattiva. Test -t 0o -t 2è il modo corretto per sapere se lo script è in esecuzione in un terminale, che è diverso dall'essere interattivo.
Gilles 'SO- smetti di essere malvagio' il

0

Utilizzare la variabile bash $ SHLVL per rilevare il livello di annidamento della shell. In uno script eseguito 'raw' facendo doppio clic sarà 1, in uno script eseguito all'interno di un terminale sarà 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

0

Sebbene la risposta dei riccioli d'oro sia probabilmente corretta nel caso tipico, sembra che ci siano casi limite. Nel mio caso, il mio xserver è configurato per l'avvio da tty1e non lascia mai tty. Se Xorg's stdoutè un TTY, allora i client avranno quel TTY collegato al loro descrittore di file per impostazione predefinita.

Ecco come ho risolto il mio 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

Non l'ho testato per vedere se funziona su una configurazione X più standard e dubito fortemente che questo sia l'unico caso limite. Se qualcuno trova una soluzione più generalmente applicabile, torna indietro e comunicacelo.


-2

Un altro, utilizzando le opzioni impostate bash variabile interna, $-.

Da .bashrc,

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

una shell interattiva non è necessariamente connessa a un terminale. mentre uno ha iniziato con quella connessione viene avviato automaticamente interattivo, anche questo è possibile: cmd | sh -i | cmd.
Mikeserv,

Questo codice viene eseguito in uno script. Non sarà interattivo, anche se è in esecuzione in un terminale.
Gilles 'SO- smetti di essere malvagio' il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.