Wie kann ein Bash-Skript erkennen, wie es ausgeführt wurde?

Wie kann ein Bash-Skript erkennen, wie es ausgeführt wurde?

Ich habe versucht, ein Bash-Skript zu erstellen, das mir dabei helfen sollte, einen ziemlich komplexen Befehl mit kleinen Änderungen auszuführen, zu denen ich per Echo und Lesen aufgefordert werde.

Ich habe Lösungen gefunden, um es zu zwingen, ein Terminal auszuführen, um den Befehl auszuführen, aber daran bin ich nicht interessiert. Ich möchte, dass es, wenn ich es ausschalte und in Nautilus einfach die Eingabetaste drücke (damit es mit „Software ausführen“ läuft), einfach sanft eine Benachrichtigung anzeigt, die besagt: „Bitte führen Sie dies von einem Terminal aus aus.“

Ich kann das Popup aufrufen – ich kenne den Befehl –, aber ich kann das Bash-Skript nicht dazu bringen, zu erkennen, ob es in einem Terminal ausgeführt wird oder nicht. Es scheint immer so zu denken. Ist das überhaupt möglich?

Antwort1

Von man bashunterBEDINGTE AUSDRÜCKE:

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

Vorausgesetzt, fd 1 ist der Standardausgang, if [ -t 1 ]; thensollte es für Sie funktionieren.Erweitertes Shell-Scripting-Handbuchbehauptet, dass -tbei Verwendung dieser Methode ein Failover auftritt sshund dass der Test (unter Verwendung von stdin, nicht stdout) daher wie folgt lauten sollte:

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

-ptestet, ob eine Datei vorhanden ist und ob es sich um eine benannte Pipe handelt. Jedoch, ich möchte anmerken, dass dies erfahrungsgemäß für mich nicht zutrifft: -p /dev/stdinschlägt sowohl bei normalen Terminals als auch bei SSH-Sitzungen fehl, während if [ -t 0 ](oder -t 1) in beiden Fällen funktioniert (siehe auch Gilles Kommentare weiter unten zu Problemen in diesem Abschnitt desErweitertes Shell-Scripting-Handbuch).


Wenn das Hauptproblem ein spezieller Kontext ist, aus dem Sie das Skript aufrufen möchten, damit es sich in einer für diesen Kontext angemessenen Weise verhält, können Sie alle diese Formalitäten umgehen und sich einiges an Aufwand ersparen, indem Sie einen Wrapper und eine benutzerdefinierte Variable verwenden:

!#/bin/bash

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

Rufen Sie dies live_script.shoder was auch immer auf und doppelklicken Sie stattdessen darauf. Sie könnten dasselbe natürlich auch mit Befehlszeilenargumenten erreichen, aber Sie würden trotzdem einen Wrapper benötigen, damit Point-and-Click in einem GUI-Dateibrowser funktioniert.

Antwort2

Verwenden Sie die Bash-Variable $SHLVL, um den Verschachtelungsgrad der Shell zu ermitteln. In einem Skript, das „raw“ durch Doppelklicken ausgeführt wird, ist es 1, in einem Skript, das in einem Terminal ausgeführt wird, ist es 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

Hinweis: Beim Testen numerischer Variablen innerhalb von (( )) ist $ nicht erforderlich.

Antwort3

Obwohl die Antwort von Goldilocks im Normalfall wahrscheinlich richtig ist, scheint es doch Sonderfälle zu geben. In meinem Fall ist mein XServer so konfiguriert, dass er von tty1diesem TTY startet und es nie verlässt. Wenn es sich bei Xorg stdoutum ein TTY handelt, scheint es, dass die Clients dieses TTY standardmäßig mit ihrem Dateideskriptor verknüpft haben.

So habe ich mein Problem gelöst:

#!/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

Ich habe nicht getestet, ob es auf einer standardmäßigeren X-Konfiguration funktioniert, und ich bezweifle auch sehr, dass dies der einzige Sonderfall ist. Wenn jemand eine allgemeiner anwendbare Lösung findet, kommen Sie bitte zurück und teilen Sie es uns mit.

Antwort4

Eine andere Möglichkeit besteht darin, mithilfe der Bash-Optionen interne Variablen festzulegen $-.

Aus .bashrc,

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

verwandte Informationen