Führen Sie komplexe Befehle im Bash-Skript aus

Führen Sie komplexe Befehle im Bash-Skript aus

Ich versuche, den folgenden Befehl in einem Bash-Skript auszuführen:

rm -rf `ls -t ${FOLDER}/other_folder | awk 'NR>5'`

Und ich versuche so etwas wie:

RM_CMD="$(rm -rf 'ls -t ${FOLDER}/other_folder | awk NR>5')"

Das wird später in einer Funktion verwendet, in der der Befehl tatsächlich ausgeführt werden soll.

Ich habe mehrere Varianten ausprobiert, aber es schlägt immer fehl. Was ist hier der richtige Ansatz?

-bearbeiten-

Weitere Informationen

Wenn ich so etwas versuche wie

RM_CMD="rm -rf `ls -t ${FOLDER}/other_folder | awk 'NR>5'`"

Es scheint zu versuchen, den Befehl sofort auszuführen, was nicht meine Absicht ist (ich möchte den richtigen Befehl zur späteren Ausführung speichern), aber es erhält alle richtigen Werte, d. h. nichts Leeres.

-Bearbeiten 2-

Ich habe versucht, die Befehle so weit wie möglich aufzuteilen, und zwar wie folgt:

LS_CMD="ls -t ${FOLDER}/other_folder"    
AWK_CMD="awk 'NR>5' ${LS_CMD}"    
RM_CMD="rm -rf '${AWK_CMD}'"

Es tritt jedoch folgendes Problem auf:

+ ssh -t user@server 'rm -rf '\''awk '\''NR>5'\'' ls -t /full/path/to/folder/other_folder'\'''
bash: 5 ls -t /full/path/to/folder/other_folder: No such file or directory

Antwort1

Normalerweise lautet die Antwort auf solche Fragen:BashFAQ Nr. 50: „Ich versuche, einen Befehl in eine Variable einzufügen, aber die komplexen Fälle schlagen immer fehl!“. Kurze Zusammenfassung: Variablen sind für Daten, nicht für ausführbaren Code, und der Versuch, Code in sie einzufügen, bringt alle möglichen Probleme mit sich.

Aber in diesem Fall gibt es noch einen weiteren kritischen Faktor: Sie werden den Befehl über ausführen ssh, was bedeutet, dass er an das Remote-System übergeben wirdals Datenund von einer Shell auf dem Remotecomputer als Befehl analysiert. Dies bedeutet, dass es sinnvoll ist, den Befehl (als Daten) in einer Variablen im Skript (auf dem lokalen Computer) zu speichern.

Für mich sieht es so aus, als ob Ihr größtes Problem darin besteht, dass bei Verwendung von Backquotes oder $( )(und diese stehen nicht in einfachen Anführungszeichen) der darin enthaltene Befehl sofort (auf dem lokalen Computer) ausgeführt und seine Ausgabe in der Variable gespeichert wird. Um dies zu vermeiden, können Sie die entsprechenden Zeichen beim Definieren der Variable maskieren:

RM_CMD="rm -rf \$(ls -t '${FOLDER}/other_folder' | awk 'NR>5')"

Beachten Sie, dass ich $( )anstelle von Backquotes verwendet habe, da dies im Allgemeinen bevorzugt wird. Es sieht für mich so aus, als hätten Sie an einigen Stellen Backquotes mit einfachen Anführungszeichen verwechselt; sie sehen ähnlich aus, haben aber völlig unterschiedliche Auswirkungen. $( )bewirkt im Wesentlichen dasselbe, ist aber optisch nicht mehrdeutig.

Außerdem gehe ich davon aus, ${FOLDER}dass es sich um eine Variable auf dem lokalen Computer handelt, die also sofort erweitert werden muss (und ich habe einfache Anführungszeichen darum gesetzt, falls sie Leerzeichen oder andere Shell-Metazeichen enthält); wenn sie von der Remote-Shell erweitert werden soll, verwenden Sie \"\${FOLDER|/other_folder\"stattdessen. Tatsächlich funktioniert das Setzen von einfachen Anführungszeichen ${FOLDER}nicht, wenn sie selbst einfache Anführungszeichen enthält. Es gibt eine Möglichkeit, dies zu beheben, aber ich habe mich hier nicht darum gekümmert.

Sie könnten bei der Variablenzuweisung auch einfache Anführungszeichen verwenden, aber dann würden Sie mit den einfachen Anführungszeichen im awkBefehl Probleme bekommen (es gibt keine saubere Möglichkeit, einfache Anführungszeichen in einer Zeichenfolge in einfachen Anführungszeichen zu verschachteln) und es gibt keine saubere Möglichkeit, sie auf dem lokalen Computer zu erweitern ${FOLDER}. Diese Probleme sind mit gemischten Anführungszeichen lösbar, aber es ist chaotisch.

Wenn Sie die Variable verwenden, sollten Sie sie schließlich in Anführungszeichen setzen:

ssh -t user@server "$RM_CMD"

... das sollte in diesem speziellen Fall keine Rolle spielen, aber bei Variablenreferenzen, die nicht in doppelte Anführungszeichen gesetzt sind, kann allerhand schiefgehen, daher empfiehlt es sich im Allgemeinen, sie in doppelte Anführungszeichen zu setzen.

Antwort2

Sie können häufige Fehler in Bash-Skripten überprüfen mitShellCheck, das online funktioniert, aber auch alsOffline-Programm. Es unterstützt verschiedene Shells (gekennzeichnet durch Shebang) und gibt auch stilistische Warnungen aus (wie in Ihrem Fall, diese $(...)anstelle von Backticks zu verwenden). Sie können Ihren eingefügten Code auch live bearbeiten und sehen, wie er bewertet wird (hilfreich in Kombination mit normalen Tutorials zum Programmierstil).

verwandte Informationen