Verhindern, dass ein Befehl nach einem anderen Befehl ausgeführt wird

Verhindern, dass ein Befehl nach einem anderen Befehl ausgeführt wird

Ich möchte, dass die Shell mich vor möglichen Fehlern warnt, die ich machen werde.

Wie kann ich verhindern, dass ein Befehl cmd2danach ausgeführt wird cmd1?

Zum Beispiel:

$ tar tf file.tar
$ rm !$

Hier habe ich einfach vergessen, dass ich die Datei aufgelistet habe, anstatt ihren Inhalt zu extrahieren.

Ich suche nach einer allgemeinen Lösung, die eine Auswahl basierend auf dem Namen und dem Rückgabewert des vorherigen Befehls und dem aktuellen Befehl trifft.

Antwort1

In Bash können Sie festlegen shopt -s histverify, dass der Verlauf nicht in einem Schritt erweitert und ausgeführt wird. Hier würde das obige beim ersten Drücken von $ rm !$erweitert , sodass Sie es überprüfen oder bearbeiten können, bevor Sie zum Ausführen erneut drücken. Eine allgemeinere Lösung würde in folgendes übergehen:$ rm file.tarEnterEnter
„Tu, was ich meine“Territorium, das ein Programm erfordert, das Ihre Absichten erahnt.

Antwort2

Mit einer allgemeinen Antwort verlangen Sie viel, aber es sollte bis zu einem gewissen Grad relativ einfach möglich sein, dies umzusetzen.

Es gibt jedoch bashmindestens zwei allgemeine Mechanismen, die dieses Problem lösen können. Sie können die Variable PROMPT_COMMAND festlegen. Diese wird dann nach allem ausgeführt, was Sie in Ihrer Eingabeaufforderung ausführen:

$ PROMPT_COMMAND='echo BOFH says hi!'
BOFH says hi!
$ man man
BOFH says hi!
$

Damit können wir den zuletzt eingegebenen Befehl speichern und ihn dann erneut lesen, um ihn für die spätere Verwendung im Speicher abzulegen (die Verlaufserweiterung funktioniert in diesem Fall nicht):

$ PROMPT_COMMAND='history -a; tail -n1 ~/.bash_history'
PROMPT_COMMAND='history -a; tail -n1 ~/.bash_history'
$ wc < test.sh | grep .
 5 11 63
wc < test.sh | grep .

Jetzt kommt der logische Teil, der ganz Ihnen überlassen ist. Lassen Sie uns einfach eine sehr vereinfachte Logik verwenden, um das Beispiel in der Frage zu vermeiden. Denken Sie daran, dass Bash-Funktionen dort immer noch funktionieren, Sie müssen also nicht alles in eine einzige Zeile, in eine einzige Variable stopfen.

$ # define the logic check
$ checkSanity() { grep -q "tar  *[tf][[:alpha:]]*[tf] " <<< "$@" && echo "be careful, don't delete this"; }
checkSanity() { grep -q "tar  *[tf][[:alpha:]]*[tf] " <<< "$@" && echo "be careful, don't delete this"; }
$ # feed it the last command
$ PROMPT_COMMAND='history -a; last=$(tail -n1 ~/.bash_history); checkSanity "$last"'
$ # simple test
$ tar tf test.sh 2>/dev/null 
be careful, don't delete this
$ tar xf test.sh 2>/dev/null 
$

Natürlich ist dieser Ansatz nützlich, um PEBKAC zu verhindern (insbesondere, wenn Sie es sleep 3am Ende hinzufügen), aber er kann den nächsten Befehl nicht allein unterbrechen.

Wenn dasWirklichwas Sie wollen, fangen Sie das DEBUGSignal ab (z. B. trap 'echo "I am not deterministic, haha"' DEBUG), da es vorher läuft. Seien Sie vorsichtig bei der Kombination dieser beiden Ansätze, da die Ausgabe/Aktion verdoppelt wird:

$ df
/.../
$ trap 'tail -n1 ~/.bash_history' DEBUG
df
df
trap 'tail -n1 ~/.bash_history' DEBUG
trap 'tail -n1 ~/.bash_history' DEBUG

Damit die Falle einen Befehl unterbricht, müssen Sie extdebug( shopt -s extdebug) aktivieren. Sie müssen den Verlauf auch nicht ständig speichern und erneut lesen, sondern können prüfen, $BASH_COMMANDob der Befehl ausgeführt werden soll. Dann müssen Sie nur sicherstellen, dass der Logikprüfer 1 zurückgibt, wenn er etwas Schlechtes erkennt, und andernfalls 0.

          extdebug
                  If set, behavior intended for use by debuggers is enabled:
    /.../
                  2.     If  the command run by the DEBUG trap returns a non-zero value, the next
                         command is skipped and not executed.


$ checkSanity() { if grep -q "tar  *[tf][[:alpha:]]*[tf] " <<< "$1"; then  echo "be careful, don't delete this"; return 1; fi; }
$ trap 'checkSanity "$BASH_COMMAND"' DEBUG
$ # simple test
$ tar tf test.sh 2>/dev/null 
be careful, don't delete this
$ tar xf test.sh 2>/dev/null 
$

Antwort3

In diesem Fall würden Sie von den Fehlerwarnungen des rmBefehls profitieren.

In Ihren Shell-Initialisierungsskripten (vorausgesetzt bash, also ~/.bashrc) können Sie rmentweder -ioder einen Alias ​​für verwenden -I.

alias rm="rm -i"

Ausman 1 rm

   -i     prompt before every removal

   -I     prompt once before removing more than three files, or when
          removing recursively.  Less intrusive than -i, while still
          giving protection against most mistakes

Die allgemeinere Frage „Wie schütze ich mein System vor mir selbst?“ wurdebereits besprochen. Kurzgesagt,Achten Sie darauf, was Sie tun, und führen Sie Befehle nur aus, rootwenn es nötig ist.

Antwort4

In Ihrem speziellen Fall würde ich Folgendes tun:

tar tf file.tar
if [ -f file ]; then   # Assuming you meant to extract a file
  rm -f file.tar
else
  echo "file is missing. Command failed."
fi

Wenn Sie nach Fehlern suchen und den nächsten Befehl nur ausführen möchten, wenn der erste erfolgreich war

some_command && another_command

Obwohl in Ihrem speziellen Fall der zweite Befehl trotzdem ausgeführt würde, da kein Fehler aufgetreten ist, auch wenn er nicht das gewünschte Ergebnis geliefert hat.

verwandte Informationen