GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Wann soll eine Shell-Variable in Anführungszeichen gesetzt werden?

Allgemeine Regel:Zitieren Sie es, wenn es entweder leer sein oder Leerzeichen (oder wirklich Leerzeichen) oder Sonderzeichen (Wildcards) enthalten kann. Strings nicht mit Leerzeichen zu zitieren führt oft dazu, dass die Shell ein einzelnes Argument in viele aufteilt.

$? benötigt keine Anführungszeichen, da es sich um einen numerischen Wert handelt. Ob $URL braucht, hängt davon ab, was Sie dort zulassen und ob Sie immer noch ein Argument wollen, wenn es leer ist.

Ich neige dazu, Zeichenfolgen immer nur aus Gewohnheit zu zitieren, da es so sicherer ist.


Kurz gesagt, zitieren Sie alles, wo Sie die Shell nicht benötigen, um Token-Splitting und Wildcard-Erweiterung durchzuführen.

Einfache Anführungszeichen schützen den Text dazwischen wörtlich. Es ist das richtige Werkzeug, wenn Sie sicherstellen müssen, dass die Schale die Saite überhaupt nicht berührt. Normalerweise ist dies der bevorzugte Zitiermechanismus, wenn Sie keine variable Interpolation benötigen.

$ echo 'Nothing \t in here $will change'
Nothing \t in here $will change

$ grep -F '@&$*!!' file /dev/null
file:I can't get this @&$*!! quoting right.

Doppelte Anführungszeichen sind geeignet, wenn eine variable Interpolation erforderlich ist. Mit geeigneten Anpassungen ist es auch ein guter Workaround, wenn Sie einfache Anführungszeichen im String benötigen. (Es gibt keinen direkten Weg, ein einfaches Anführungszeichen zwischen einfachen Anführungszeichen zu maskieren, da es innerhalb einfacher Anführungszeichen keinen Escape-Mechanismus gibt – wenn es einen gäbe, würden sie nicht vollständig wörtlich zitieren.)

$ echo "There is no place like '$HOME'"
There is no place like '/home/me'

Keine Anführungszeichen sind geeignet, wenn Sie ausdrücklich verlangen, dass die Shell Token-Splitting und/oder Wildcard-Erweiterung durchführt.

Token-Splitting;

 $ words="foo bar baz"
 $ for word in $words; do
 >   echo "$word"
 > done
 foo
 bar
 baz

Im Gegensatz dazu:

 $ for word in "$words"; do echo "$word"; done
 foo bar baz

(Die Schleife läuft nur einmal über die einzelne Zeichenfolge in Anführungszeichen.)

 $ for word in '$words'; do echo "$word"; done
 $words

(Die Schleife läuft nur einmal über die wörtliche Zeichenfolge in einfachen Anführungszeichen.)

Wildcard-Erweiterung:

$ pattern='file*.txt'
$ ls $pattern
file1.txt      file_other.txt

Im Gegensatz dazu:

$ ls "$pattern"
ls: cannot access file*.txt: No such file or directory

(Es gibt keine Datei mit dem wörtlichen Namen file*.txt .)

$ ls '$pattern'
ls: cannot access $pattern: No such file or directory

(Es gibt keine Datei namens $pattern , auch nicht!)

Genauer gesagt sollte alles, was einen Dateinamen enthält, normalerweise in Anführungszeichen gesetzt werden (weil Dateinamen Leerzeichen und andere Shell-Metazeichen enthalten können). Alles, was eine URL enthält, sollte normalerweise in Anführungszeichen gesetzt werden (weil viele URLs Shell-Metazeichen wie ? enthalten und & ). Alles, was einen regulären Ausdruck enthält, sollte normalerweise in Anführungszeichen gesetzt werden (dito dito). Alles, was signifikante Leerzeichen enthält, außer einzelnen Leerzeichen zwischen Nicht-Leerzeichen, muss in Anführungszeichen gesetzt werden (weil die Shell sonst die Leerzeichen effektiv in einzelne Leerzeichen zerlegt und alle führenden oder nachgestellten Leerzeichen kürzt).

Wenn Sie wissen, dass eine Variable nur einen Wert enthalten kann, der keine Shell-Metazeichen enthält, sind Anführungszeichen optional. Also ein nicht in Anführungszeichen gesetzter $? ist grundsätzlich in Ordnung, da diese Variable immer nur eine einzige Zahl enthalten kann. Jedoch "$?" ist ebenfalls korrekt und wird aus Gründen der allgemeinen Konsistenz und Korrektheit empfohlen (obwohl dies meine persönliche Empfehlung ist, keine allgemein anerkannte Richtlinie).

Werte, die keine Variablen sind, folgen grundsätzlich den gleichen Regeln, obwohl Sie dann auch alle Metazeichen maskieren könnten, anstatt sie zu zitieren. Ein allgemeines Beispiel ist eine URL mit einem & darin wird von der Shell als Hintergrundbefehl geparst, es sei denn, das Metazeichen wird maskiert oder in Anführungszeichen gesetzt:

$ wget http://example.com/q&uack
[1] wget http://example.com/q
-bash: uack: command not found

(Das passiert natürlich auch, wenn die URL in einer Variable ohne Anführungszeichen steht.) Für einen statischen String sind einfache Anführungszeichen am sinnvollsten, obwohl hier jede Form von Anführungszeichen oder Escapezeichen funktioniert.

wget 'http://example.com/q&uack'  # Single quotes preferred for a static string
wget "http://example.com/q&uack"  # Double quotes work here, too (no $ or ` in the value)
wget http://example.com/q\&uack   # Backslash escape
wget http://example.com/q'&'uack  # Only the metacharacter really needs quoting

Das letzte Beispiel deutet auch auf ein weiteres nützliches Konzept hin, das ich gerne als "Wippenzitieren" bezeichne. Wenn Sie einfache und doppelte Anführungszeichen mischen müssen, können Sie sie nebeneinander verwenden. Zum Beispiel die folgenden Strings in Anführungszeichen

'$HOME '
"isn't"
' where `<3'
"' is."

können Rücken an Rücken zusammengefügt werden und bilden nach Tokenisierung und Entfernung der Anführungszeichen eine einzige lange Zeichenfolge.

$ echo '$HOME '"isn't"' where `<3'"' is."
$HOME isn't where `<3' is.

Das ist nicht sehr gut lesbar, aber es ist eine gängige Technik und daher gut zu wissen.

Abgesehen davon sollten Skripte normalerweise nicht ls verwenden für alles. Um einen Platzhalter zu erweitern, ... verwenden Sie ihn einfach.

$ printf '%s\n' $pattern   # not ``ls -1 $pattern''
file1.txt
file_other.txt

$ for file in $pattern; do  # definitely, definitely not ``for file in $(ls $pattern)''
>  printf 'Found file: %s\n' "$file"
> done
Found file: file1.txt
Found file: file_other.txt

(Die Schleife ist im letzten Beispiel komplett überflüssig; printf funktioniert insbesondere gut mit mehreren Argumenten. stat zu. Das Schleifen über eine Wildcard-Übereinstimmung ist jedoch ein häufiges Problem und wird häufig falsch gemacht.)

Eine Variable, die eine Liste von zu durchlaufenden Tokens oder einen Platzhalter zum Erweitern enthält, wird seltener gesehen, daher kürzen wir manchmal ab, um „alles zu zitieren, es sei denn, Sie wissen genau, was Sie tun“.


Hier ist eine Drei-Punkte-Formel für Anführungszeichen im Allgemeinen:

Doppelte Anführungszeichen

In Kontexten, in denen wir Worttrennung und Globbing unterdrücken wollen. Auch in Kontexten, in denen das Literal als String behandelt werden soll, nicht als Regex.

Einfache Anführungszeichen

In Zeichenfolgenliteralen, in denen wir die Interpolation und die spezielle Behandlung von Backslashes unterdrücken möchten. Mit anderen Worten, Situationen, in denen die Verwendung doppelter Anführungszeichen unangebracht wäre.

Keine Anführungszeichen

In Kontexten, in denen wir absolut sicher sind, dass es keine Probleme mit Worttrennung oder Globbing gibt, oder wir Worttrennung und Globbing wollen .

Beispiele

Doppelte Anführungszeichen

  • literale Zeichenfolgen mit Leerzeichen ("StackOverflow rocks!" , "Steve's Apple" )
  • Variablenerweiterungen ("$var" , "${arr[@]}" )
  • Befehlsersetzungen ("$(ls)" , "`ls`" )
  • Globs, bei denen der Verzeichnispfad oder der Teil des Dateinamens Leerzeichen enthält ("/my dir/"* )
  • um einfache Anführungszeichen zu schützen ("single'quote'delimited'string" )
  • Bash-Parametererweiterung ("${filename##*/}" )

Einfache Anführungszeichen

  • Befehlsnamen und Argumente mit Leerzeichen
  • Literale Zeichenfolgen, die eine Interpolation benötigen, werden unterdrückt ( 'Really costs $$!' , 'just a backslash followed by a t: \t' )
  • um doppelte Anführungszeichen zu schützen ('The "crux"' )
  • Regex-Literale, die eine Interpolation benötigen, um unterdrückt zu werden
  • Verwenden Sie Shell-Quoting für Literale mit Sonderzeichen ($'\n\t' )
  • Verwenden Sie Shell-Quoting, wenn wir mehrere einfache und doppelte Anführungszeichen schützen müssen ($'{"table": "users", "where": "first_name"=\'Steve\'}' )

Keine Anführungszeichen

  • um numerische Standardvariablen herum ($$ , $? , $# usw.)
  • in arithmetischen Kontexten wie ((count++)) , "${arr[idx]}" , "${string:start:length}"
  • innerhalb von [[ ]] Ausdruck, der frei von Worttrennungs- und Globbing-Problemen ist (dies ist eine Frage des Stils und die Meinungen können sehr unterschiedlich sein)
  • wo wir die Wortaufteilung wollen (for word in $words )
  • wo wir Globbing wollen (for txtfile in *.txt; do ... )
  • wo wir ~ wollen zu interpretieren als $HOME (~/"some dir" aber nicht "~/some dir" )

Siehe auch:

  • Unterschied zwischen einfachen und doppelten Anführungszeichen in Bash
  • Was sind die speziellen Dollarzeichen-Shell-Variablen?
  • Zitate und Flucht - Bash Hackers' Wiki
  • Wann sind doppelte Anführungszeichen erforderlich?

Linux
  1. So setzen Sie Ihre $PATH-Variable in Linux

  2. Problem mit Shell-Variablen beim Versuch, mkdir

  3. Wie werden Zeilenumbrüche beibehalten, wenn die Befehlsausgabe in einer Variablen gespeichert wird?

  4. Probleme mit der Erweiterung von Bash-Variablen mit einfachen Anführungszeichen

  5. Wie starte ich im Einzelbenutzermodus eine zweite Shell?

So speichern Sie einen Linux-Befehl als Variable im Shell-Skript

Warum wird bei der Verwendung von Anführungszeichen ein einzelner umgekehrter Schrägstrich angezeigt?

Exportbefehl in Linux erklärt

Was ist Subshell in Linux?

Shell - Variableninhalte in eine Datei schreiben

Shell-Skript ändert Verzeichnis mit Variable