Verwendung einer Umgebungsvariablen in einer Zeichenfolge in Anführungszeichen in Bash

91

Ich habe verschiedene Formen der folgenden in einem Bash-Skript ausprobiert:

#!/bin/bash
svn diff $@ --diff-cmd /usr/bin/diff -x "-y -w -p -W $COLUMNS"

Aber ich kann die Syntax nicht bekommen, um die COLUMNSUmgebungsvariable korrekt zu erweitern .

Ich habe verschiedene Formen der folgenden ausprobiert:

svn diff $@ --diff-cmd /usr/bin/diff -x '-y -w -p -W $COLUMNS'

und

svn diff $@ --diff-cmd /usr/bin/diff -x '-y -w -p -W ${COLUMNS}'

und

eval svn diff $@ --diff-cmd /usr/bin/diff -x "-y -w -p -W $COLUMNS"

Vorschläge?

Jamie
quelle
Was bringen diese Beispiele in Ihrem Fall? Und was sollen sie produzieren?
Der Befehl außerhalb des Skripts funktioniert?
dfa
Haben Sie versuchtsvn diff $@ --diff-cmd /usr/bin/diff -x "-y -w -p -W ""$COLUMNS"
Qian Chen
Übrigens, wenn Sie $@nicht zitiert verwenden, ist es genau das Gleiche wie $*- das heißt, es wird "foo bar"in zwei separate Argumente aufgeteilt, foound bar. Wenn Sie die ursprüngliche Argumentliste so beibehalten möchten, wie sie Ihnen gegeben wurde, möchten Sie "$@".
Charles Duffy

Antworten:

16

Wenn Sie sich nicht sicher sind, können Sie die Anforderung 'cols' auf dem Terminal verwenden und COLUMNS vergessen:

COLS=$(tput cols)
TheBonsai
quelle
Aus irgendeinem Grund ist dies die einzige Lösung, mit der ich diese Seite bearbeiten konnte (Stand: 11. Mai, 10:38 Uhr ET). Danke
Jamie
390

Nur eine kurze Notiz / Zusammenfassung für alle, die über Google hierher gekommen sind und nach der Antwort auf die im Titel gestellte allgemeine Frage gesucht haben (so wie ich). Eine der folgenden Optionen sollte funktionieren, um Zugriff auf Shell-Variablen in Anführungszeichen zu erhalten:

echo "$VARIABLE"
echo "${VARIABLE}"

Die Verwendung von einfachen Anführungszeichen ist das Hauptproblem. Gemäß dem Bash-Referenzhandbuch :

Durch das Einschließen von Zeichen in einfache Anführungszeichen ( ') wird der Literalwert jedes Zeichens in den Anführungszeichen beibehalten. Ein einfaches Anführungszeichen darf nicht zwischen einfachen Anführungszeichen stehen, selbst wenn ein Backslash vorangestellt ist. [...] Enclosing Zeichen in doppelten Anführungszeichen ( ") erhält den wörtlichen Wert aller Zeichen innerhalb der Anführungszeichen, mit Ausnahme von $, `, \, und, wenn die Geschichte Erweiterung aktiviert ist, !. Die Zeichen $und `behalten ihre besondere Bedeutung in doppelten Anführungszeichen (siehe Shell-Erweiterungen). Der Backslash behält seine besondere Bedeutung nur , wenn sie durch eine der folgenden Zeichen folgen: $, `, ",\oder Newline. In doppelten Anführungszeichen werden Backslashes entfernt, auf die eines dieser Zeichen folgt. Backslashes vor Zeichen ohne besondere Bedeutung bleiben unverändert. Ein doppeltes Anführungszeichen kann in doppelten Anführungszeichen angegeben werden, indem ein Backslash vorangestellt wird. Wenn diese Option aktiviert ist, wird die Verlaufserweiterung durchgeführt, es sei denn, ein !in doppelten Anführungszeichen angegebenes Zeichen wird mit einem Backslash maskiert. Der Backslash vor !wird nicht entfernt. Die speziellen Parameter *und @haben in doppelten Anführungszeichen eine besondere Bedeutung (siehe Shell-Parametererweiterung).

In dem in der Frage gestellten speziellen Fall ist $ COLUMNS eine spezielle Variable mit nicht standardmäßigen Eigenschaften (siehe Antwort von lhunath oben).

RekursivIronic
quelle
19
Im Fall von einfachen Anführungszeichen hilft möglicherweise diese Problemumgehung: 'before'"$variable"'after'(wie in dieser Antwort angegeben: stackoverflow.com/a/13802438/2254346 )
MakisH
Gute Antwort! Ich hatte das gleiche Problem, meine env-Variable in einfache Anführungszeichen zu verweisen. Nachdem ich mein einfaches Anführungszeichen in doppelte Anführungszeichen geändert hatte, wurde meine env-Variable wie erwartet erweitert.
Binita Bharati
14

Beachten Sie, dass COLUMNS:

  1. KEINE Umgebungsvariable. Es ist ein gewöhnlicher Bash-Parameter, der von Bash selbst festgelegt wird.
  2. Wird beim Empfang eines SIGWINCHSignals automatisch eingestellt .

Dieser zweite Punkt bedeutet normalerweise, dass Ihre COLUMNSVariable nur in Ihrer interaktiven Shell festgelegt wird, nicht in einem Bash-Skript.

Wenn Ihr Skript stdinmit Ihrem Terminal verbunden ist, können Sie die Breite Ihres Terminals manuell nachschlagen, indem Sie Ihr Terminal fragen:

tput cols

Und um dies in Ihrem SVN-Befehl zu verwenden:

svn diff "$@" --diff-cmd /usr/bin/diff -x "-y -w -p -W $(tput cols)"

(Hinweis: Sie sollten zitieren "$@" und sich fernhalten eval;-))

lhunath
quelle
Danke für die Auskunft; Zu wissen, was los ist, bringt ein Gefühl der Katharsis in das Problem.
Jamie
1

Das folgende Skript funktioniert für mich für mehrere Werte von $COLUMNS. Ich frage mich, ob Sie nicht COLUMNSvor diesem Anruf einstellen ?

#!/bin/bash
COLUMNS=30
svn diff $@ --diff-cmd /usr/bin/diff -x "-y -w -p -W $COLUMNS"

Können Sie $COLUMNSin Ihrem Skript nachsehen, ob es richtig eingestellt ist?

Alex B.
quelle
Boo, hiss re: unquoted $@- das teilt einen einzelnen Parameter "two words"in zwei separate Parameter auf, twound words. Sollte sein "$@", die Argumentliste genau so durchzuleiten, wie sie angegeben wurde.
Charles Duffy
0

Du machst es richtig, also denke ich, dass etwas anderes schuld ist (keine SPALTEN exportieren?).

Ein Trick, um diese Fälle zu debuggen, besteht darin, einen speziellen Befehl zu erstellen (ein Abschluss für Programmiersprachen-Leute). Erstellen Sie ein Shell-Skript mit dem Namen diff-column.

exec /usr/bin/diff -x -y -w -p -W "$COLUMNS" "$@"

und einfach benutzen

svn diff "$@" --diff-cmd  diff-columns

Auf diese Weise ist Ihr Code übersichtlicher zu lesen und modularer (Top-Down-Ansatz), und Sie können den Diff-Spalten-Code gründlich separat testen (Bottom-Up-Ansatz).

Colas Nahaboo
quelle
Die Befehlszeile wird analysiert, bevor der Prozess verzweigt wird. Daher kann es nicht das Problem sein, COLUMNS nicht zu exportieren.
Peter van der Heijden
1
Er sagt seinen Code in einem Teil eines Bash-Skripts, daher kann es das Problem sein.
Colas Nahaboo