Warum verhält sich dieser GPG-Befehl in einem Skript anders, wenn er in eine Shell eingefügt wird?

Warum verhält sich dieser GPG-Befehl in einem Skript anders, wenn er in eine Shell eingefügt wird?

Hier ist ein Skript, das eine Datei nacheinander mit zwei verschiedenen symmetrischen Chiffren symmetrisch verschlüsselt/entschlüsselt.

#!/bin/bash

if [ "$#" -ne 2 ]; then
    echo "Arguments: enc|dec filename"
    exit
fi

E="gpg -o - --symmetric --cipher-algo"
D="gpg -o - --decrypt"
ERR="2>/dev/null"

if [ "$1" = "enc" ]; then
    $E AES $2 | $E TWOFISH -
elif [ "$1" = "dec" ]; then
    $D $2 ${ERR} | $D - ${ERR}
else
    echo "Arguments: enc|dec filename"
    exit
fi

Beim Ausführen ./doublecrypt dec /tmp/test.encryptederhalte ich die Fehler

usage: gpg [options] --decrypt [filename]
usage: gpg [options] --decrypt [filename]

Wenn ich die Zeile ändere

$D $2 ${ERR} | $D - ${ERR}

Zu

echo "$D $2 ${ERR} | $D - ${ERR}"

Es druckt

gpg -o - --decrypt /tmp/xenc 2>/dev/null | gpg -o - --decrypt - 2>/dev/null

Wenn ich dies kopiere und in Bash einfüge, läuft es korrekt.

Warum funktioniert es also nicht, wenn ich es entferne echound es, wie in der Originalform, direkt vom Bash-Skript auswerten lasse?

Ich verwende Ubuntu Saucy und Bash ist meine Shell.

Antwort1

Kurze Antwort: sieheBashFAQ Nr. 50: Ich versuche, einen Befehl in eine Variable einzufügen, aber die komplexen Fälle schlagen immer fehl!.

Lange Antwort: Sie geraten wegen der Reihenfolge, in der die Shell verschiedene Elemente von Befehlszeilen analysiert, in Schwierigkeiten. Insbesondere erweitert sie Variablenreferenzen (wie ${ERR}) etwa in der Mitte des Prozesses – nachdem sie bereits Dinge wie Anführungszeichen, Escapezeichen und Umleitungen behandelt hat. In Ihrem Fall ist der Umleitungsteil wichtig: Bis die Shell ${ERR}in erweitert 2>/dev/null, hat sie bereits nach Umleitungen gesucht und keine gefunden, also behandelt sie es einfach 2>/dev/nullals Argument für den Befehl und gpglehnt es dann als sinnlos ab.

Grundsätzlich ist das Speichern von Befehlen (oder Befehlselementen) in Variablen der falsche Weg. Variablen sind für Daten gedacht, nicht für ausführbaren Code. In diesem Fall wäre es viel besser, stattdessen Funktionen zu verwenden:

e() {
    gpg -o - --symmetric --cipher-algo "$@"
}
d() {
    gpg -o - --decrypt "$@" 2>/dev/null
}

if [ "$1" = "enc" ]; then
    e AES "$2" | e TWOFISH -
elif [ "$1" = "dec" ]; then
    d "$2" | d -
else
    echo "Arguments: enc|dec filename"
    exit
fi

Beachten Sie, dass ich es auch $2in Anführungszeichen gesetzt habe, um zu verhindern, dass der Wert der zweiten Hälfte des Shell-Analyseprozesses unterzogen wird.

Antwort2

Versuchen Sie es mit einer Änderung $D $2 ${ERR} | $D - ${ERR}zu:

$( $D $2 ${ERR} | $D - ${ERR} )

Verwenden Sie außerdem den vollständigen Pfad zu Ihrem gpgProgramm, zB:

/usr/local/bin/gpg

verwandte Informationen