Quand enrouler des guillemets autour d'une variable shell?

est-ce que quelqu'un pourrait me dire si oui ou non je devrais enrouler des citations autour de variables dans un script shell?

, par exemple, est la suivante:

xdg-open $URL 
[ $? -eq 2 ]

ou

xdg-open "$URL"
[ "$?" -eq "2" ]

et si oui, pourquoi?

91
demandé sur codeforester 2012-04-09 03:02:08

5 réponses

règle générale: citez-la si elle peut être vide ou contenir des espaces (ou n'importe quel espace vraiment) ou des caractères spéciaux (caractères génériques). Le fait de ne pas citer des chaînes avec des espaces conduit souvent le shell à séparer un seul argument en plusieurs.

$? n'a pas besoin de guillemets puisque c'est une valeur numérique. Si $URL a besoin, cela dépend de ce que vous autorisez là-dedans et si vous voulez toujours un argument s'il est vide.

j'ai tendance à toujours citation cordes juste de sortir de l'habitude, car il est plus sûr de cette façon.

58
répondu paxdiablo 2018-02-08 11:15:25

en bref, citez tout où vous n'avez pas besoin de l'interpréteur de commandes pour effectuer le dédoublement de jeton et l'expansion de Joker.

les guillemets simples protègent le texte entre eux mot à mot. C'est l'outil approprié quand vous avez besoin de vous assurer que le shell ne touche pas la corde du tout. Typiquement, c'est le mécanisme de citation de choix quand vous n'avez pas besoin d'interpolation variable.

$ 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.

les doubles guillemets conviennent lorsque la variable l'interpolation est nécessaire. Avec des adaptations appropriées, c'est aussi une bonne solution lorsque vous avez besoin de guillemets simples dans la chaîne. (Il n'y a pas de moyen simple d'échapper à une citation unique entre des citations simples, parce qu'il n'y a pas de mécanisme d'évasion à l'intérieur des citations simples -- s'il y en avait, ils ne citeraient pas complètement mot à mot.)

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

aucun devis ne convient lorsque vous avez spécifiquement besoin de l'interpréteur de commandes pour effectuer le dédoublement de jeton et / ou l'extension de Joker.

jeton splitting;

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

par contraste:

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

(la boucle ne s'exécute qu'une seule fois, sur la chaîne simple, citée.)

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

(la boucle ne s'exécute qu'une seule fois, sur la chaîne littérale simple citée.)

extension de Joker:

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

par contraste:

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

(il n'y a pas de fichier nommé littéralement file*.txt .)

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

(il n'y a pas non plus de fichier nommé $pattern !)

en termes plus concrets, tout ce qui contient un nom de fichier doit généralement être cité (parce que les noms de fichiers peuvent contenir des espaces et d'autres métacharactères shell). Tout ce qui contient une URL doit généralement être cité (car de nombreuses URLs contiennent des métacharges de shell comme ? et & ). Tout ce qui contient un regex doit généralement être cité (idem idem idem idem). Tout ce qui contient des espaces blancs significatifs autres que des espaces simples entre des caractères autres que des espaces blancs doit être cité (parce que sinon, le shell munge l'espace blanc en, effectivement, des espaces simples, et couper tout espace blanc menant ou traînant).

Lorsque vous savez qu'une variable ne peut contenir qu'une valeur qui ne contient pas de shell métacaractères, citant est facultatif. Ainsi, une variable non cotée $? est fondamentalement bien, parce que cette variable peut ne jamais contenir un numéro unique. Cependant, "$?" est également correct, et recommandé pour la cohérence générale et l'exactitude (bien que ce soit ma recommandation personnelle, pas une politique largement reconnue).

les valeurs qui ne sont pas des variables suivent essentiellement les mêmes règles, bien que vous puissiez alors également échapper à tout metacharacters au lieu de les citer. Pour un exemple courant, une URL avec un & en elle sera analysée par le shell comme une commande de fond à moins que le metacharacter est échappé ou cité:

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

(bien sûr, cela arrive aussi si L'URL est dans une variable non cotée.) Pour une chaîne statique, les guillemets simples ont le plus de sens, bien que toute forme de citation ou d'évasion des œuvres ici.

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

le dernier exemple suggère également un autre concept utile, que j'aime appeler"Seesaw citant". Si vous avez besoin de mélanger les guillemets simples et doubles, vous pouvez les utiliser adjacents les uns aux autres. Pour exemple, les chaînes suivantes citées

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

peut être collé ensemble dos à dos, formant une seule longue chaîne après tokenization et la suppression de citation.

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

ce n'est pas terriblement lisible, mais c'est une technique commune et donc bon à savoir.

mis à part, les scripts ne doivent généralement pas utiliser ls pour quoi que ce soit. pour étendre un joker, juste ... utiliser.

$ 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

(la boucle est complètement superflue dans ce dernier exemple; printf fonctionne spécifiquement très bien avec des arguments multiples. stat aussi. Mais la boucle au-dessus d'une correspondance de Joker est un problème commun, et souvent fait incorrectement.)

une variable contenant une liste de tokens à boucler ou un joker à étendre est moins souvent vu, donc nous abrégeons parfois pour"tout citer sauf si vous savez exactement ce que vous faites".

48
répondu tripleee 2017-04-12 06:20:49

Voici une formule en trois points pour les citations en général:

double guillemets

dans les contextes où nous voulons supprimer le dédoublement de mots et le globbing. Aussi dans les contextes où nous voulons que le littéral soit traité comme une chaîne, pas comme un regex.

apostrophes

dans string literals où nous voulons supprimer l'interpolation et le traitement spécial des barres obliques inverses. En d'autres termes, les situations où l'utilisation de guillemets serait inappropriée.

Pas de guillemets

dans les contextes où nous sommes absolument sûrs qu'il n'y a pas de problèmes de partage de mots ou de globbing ou nous ne veulent pas de partage de mots et globbing .


exemples

Double citations

  • cordes littérales avec espace blanc ( "StackOverflow rocks!" , "Steve's Apple" )
  • extensions variables ( "$var" , "${arr[@]}" )
  • substitutions de commandes ( "$(ls)" , "`ls`" )
  • globs lorsque la partie chemin d'accès ou nom de fichier inclut des espaces ( "/my dir/"* )
  • pour protéger les citations simples ( "single'quote'delimited'string" )
  • Bash expansion du paramètre ( "${filename##*/}" )

apostrophes

  • les noms de commandes et les arguments qui ont des espaces en eux
  • cordes littérales qui ont besoin d'interpolation pour être supprimé ( 'Really costs $$!' , 'just a backslash followed by a t: \t' )
  • pour protéger les doubles citations ( 'The "crux"' )
  • regex littéraux qui ont besoin d'interpolation être supprimée
  • utiliser shell citation pour les littérales impliquant des caractères spéciaux ( $'\n\t' )
  • utilisez shell citant où nous devons protéger plusieurs guillemets simples et doubles ( $'{"table": "users", "where": "first_name"=\'Steve\'}' )

Pas de guillemets

  • autour des variables numériques standard( $$ , $? , $# etc.)
  • dans des contextes arithmétiques comme ((count++)) , "${arr[idx]}" , "${string:start:length}"
  • inside [[ ]] expression qui est libre de la division de mots et des questions globbing (il s'agit d'une question de style et les opinions peuvent varier grandement)
  • où nous voulons la division de mot ( for word in $words )
  • où nous voulons d'expansion ( for txtfile in *.txt; do ... )
  • où nous voulons ~ être interprété comme $HOME ( ~/"some dir" , mais pas "~/some dir" )

Voir aussi:

8
répondu codeforester 2018-09-21 00:15:42

j'utilise généralement cité comme "$var" pour sûr, sauf si je suis sûr que $var ne contiennent pas d'espace.

je ne l'utilisation de $var comme un moyen simple de rejoindre les lignes:

lines="`cat multi-lines-text-file.txt`"
echo "$lines"                             ## multiple lines
echo $lines                               ## all spaces (including newlines) are zapped
1
répondu Bach Lien 2018-01-16 17:14:26

pour l'utilisation des variables dans le script shell, utilisez "" les variables citées en tant que variables citées signifie que la variable peut contenir des espaces ou des caractères spéciaux qui n'affecteront pas l'exécution de votre script shell. Sinon, si vous êtes sûr de ne pas avoir d'espaces ou de caractère spécial dans votre nom de variable, alors vous pouvez les utiliser sans " ".

exemple:

echo "$nom de l'url" -- ( Peut être utilisé en tout temps )

echo " $url nom "-- (ne peut pas être utilisé dans de telles situations, il faut donc prendre des précautions avant de l'utiliser)

0
répondu Vipul Sharma 2018-09-21 03:47:09