Regla general:cítelo si puede estar vacío o contener espacios (o cualquier espacio en blanco en realidad) o caracteres especiales (comodines). No citar cadenas con espacios a menudo hace que el shell divida un solo argumento en muchos.
$?
no necesita comillas ya que es un valor numérico. Si $URL
las necesidades dependen de lo que permita allí y si aún desea un argumento si está vacío.
Tiendo siempre a citar cadenas por costumbre, ya que es más seguro de esa manera.
En resumen, cite todo lo que no requiera que el shell realice la división de tokens y la expansión de comodines.
Las comillas simples protegen el texto entre ellas palabra por palabra. Es la herramienta adecuada cuando necesita asegurarse de que el caparazón no toque la cuerda en absoluto. Por lo general, es el mecanismo de cotización elegido cuando no se requiere interpolación de variables.
$ 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.
Las comillas dobles son adecuadas cuando se requiere la interpolación de variables. Con las adaptaciones adecuadas, también es una buena solución cuando necesita comillas simples en la cadena. (No existe una forma sencilla de escapar de una comilla simple entre comillas simples, porque no hay un mecanismo de escape dentro de las comillas simples; si lo hubiera, no citarían completamente textualmente).
$ echo "There is no place like '$HOME'"
There is no place like '/home/me'
Las comillas no son adecuadas cuando se requiere específicamente que el shell realice la división de tokens y/o la expansión de comodines.
División de fichas;
$ words="foo bar baz"
$ for word in $words; do
> echo "$word"
> done
foo
bar
baz
Por el contrario:
$ for word in "$words"; do echo "$word"; done
foo bar baz
(El bucle solo se ejecuta una vez, sobre la única cadena entre comillas).
$ for word in '$words'; do echo "$word"; done
$words
(El bucle solo se ejecuta una vez, sobre la cadena literal entre comillas simples).
Expansión comodín:
$ pattern='file*.txt'
$ ls $pattern
file1.txt file_other.txt
Por el contrario:
$ ls "$pattern"
ls: cannot access file*.txt: No such file or directory
(No hay ningún archivo llamado literalmente file*.txt
.)
$ ls '$pattern'
ls: cannot access $pattern: No such file or directory
(No hay ningún archivo llamado $pattern
, ¡tampoco!)
En términos más concretos, cualquier cosa que contenga un nombre de archivo generalmente debe citarse (porque los nombres de archivo pueden contener espacios en blanco y otros metacaracteres de shell). Por lo general, cualquier cosa que contenga una URL debe citarse (porque muchas URL contienen metacaracteres de shell como ?
y &
). Cualquier cosa que contenga una expresión regular generalmente debe citarse (ídem, ídem). Todo lo que contenga espacios en blanco significativos que no sean espacios simples entre caracteres que no sean espacios en blanco debe estar entrecomillado (porque de lo contrario, el shell convertirá el espacio en blanco en espacios simples, de manera efectiva, y recortará cualquier espacio en blanco inicial o final).
Cuando sabe que una variable solo puede contener un valor que no contiene metacaracteres de shell, las comillas son opcionales. Por lo tanto, un $?
sin comillas está básicamente bien, porque esta variable solo puede contener un solo número. Sin embargo, "$?"
también es correcto y se recomienda por coherencia y corrección general (aunque esta es mi recomendación personal, no una política ampliamente reconocida).
Los valores que no son variables básicamente siguen las mismas reglas, aunque también podría escapar de cualquier metacaracteres en lugar de entrecomillarlos. Para un ejemplo común, una URL con un &
en él será analizado por el shell como un comando de fondo a menos que el metacarácter esté escapado o entre comillas:
$ wget http://example.com/q&uack
[1] wget http://example.com/q
-bash: uack: command not found
(Por supuesto, esto también sucede si la URL está en una variable sin comillas). Para una cadena estática, las comillas simples tienen más sentido, aunque cualquier forma de comillas o escapes funciona aquí.
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
El último ejemplo también sugiere otro concepto útil, que me gusta llamar "citas de balancín". Si necesita mezclar comillas simples y dobles, puede usarlas una al lado de la otra. Por ejemplo, las siguientes cadenas entre comillas
'$HOME '
"isn't"
' where `<3'
"' is."
se pueden pegar espalda con espalda, formando una sola cadena larga después de la tokenización y la eliminación de comillas.
$ echo '$HOME '"isn't"' where `<3'"' is."
$HOME isn't where `<3' is.
Esto no es muy legible, pero es una técnica común y, por lo tanto, es bueno saberlo.
Aparte, los scripts normalmente no deberían usar ls
por nada. Para expandir un comodín, simplemente... utilícelo.
$ 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
(El ciclo es completamente superfluo en el último ejemplo; printf
específicamente funciona bien con múltiples argumentos. stat
también. Pero repetir una coincidencia de comodines es un problema común y, con frecuencia, se realiza incorrectamente).
Una variable que contiene una lista de tokens para recorrer o un comodín para expandir se ve con menos frecuencia, por lo que a veces abreviamos para "citar todo a menos que sepa exactamente lo que está haciendo".
Aquí hay una fórmula de tres puntos para citas en general:
Comillas dobles
En contextos en los que queremos suprimir la división de palabras y la globificación. También en contextos donde queremos que el literal se trate como una cadena, no como una expresión regular.
Comillas simples
En cadenas literales donde queremos suprimir la interpolación y el tratamiento especial de las barras invertidas. En otras palabras, situaciones en las que el uso de comillas dobles sería inapropiado.
Sin comillas
En contextos en los que estamos absolutamente seguros de que no hay problemas de división de palabras o de acumulación de palabras o queremos división de palabras y acumulación de palabras .
Ejemplos
Comillas dobles
- cadenas literales con espacios en blanco (
"StackOverflow rocks!"
,"Steve's Apple"
) - expansiones variables (
"$var"
,"${arr[@]}"
) - sustituciones de comandos (
"$(ls)"
,"`ls`"
) - globs donde la ruta del directorio o la parte del nombre del archivo incluyen espacios (
"/my dir/"*
) - para proteger las comillas simples (
"single'quote'delimited'string"
) - Expansión de parámetros de Bash (
"${filename##*/}"
)
Comillas simples
- nombres de comandos y argumentos que tienen espacios en blanco
- cadenas literales que necesitan interpolación para ser suprimidas (
'Really costs $$!'
,'just a backslash followed by a t: \t'
) - para proteger las comillas dobles (
'The "crux"'
) - Literales de expresión regular que necesitan interpolación para ser suprimidos
- use comillas de shell para literales que involucren caracteres especiales (
$'\n\t'
) - usar comillas shell cuando necesitemos proteger varias comillas simples y dobles (
$'{"table": "users", "where": "first_name"=\'Steve\'}'
)
Sin comillas
- alrededor de variables numéricas estándar (
$$
,$?
,$#
etc) - en contextos aritméticos como
((count++))
,"${arr[idx]}"
,"${string:start:length}"
- dentro de
[[ ]]
expresión que está libre de división de palabras y problemas de globosidad (esto es una cuestión de estilo y las opiniones pueden variar ampliamente) - donde queremos división de palabras (
for word in $words
) - dónde queremos globbing (
for txtfile in *.txt; do ...
) - dónde queremos
~
para ser interpretado como$HOME
(~/"some dir"
pero no"~/some dir"
)
Véase también:
- Diferencia entre comillas simples y dobles en Bash
- ¿Cuáles son las variables especiales de shell del signo de dólar?
- Citas y escapes - Bash Hackers' Wiki
- ¿Cuándo son necesarias las comillas dobles?