Saltar al contenido

¿Cuándo ajustar las comillas alrededor de una variable de shell?

Al fin luego de tanto trabajar ya encontramos la solución de este contratiempo que muchos lectores de esta web han tenido. Si quieres aportar algún detalle puedes aportar tu comentario.

Solución:

Regla general: cítelo si puede estar vacío o contener espacios (o cualquier espacio en blanco) o caracteres especiales (comodines). No citar cadenas con espacios a menudo lleva a que el shell divida un solo argumento en muchos.

$? no necesita comillas ya que es un valor numérico. Si $URL necesita depende de lo que permita allí y si aún desea un argumento si está vacío.

Siempre suelo citar cadenas por costumbre, ya que así es más seguro.

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 literalmente el texto entre ellas. Es la herramienta adecuada cuando necesita asegurarse de que la carcasa no toque el string en absoluto. Normalmente, es el mecanismo de cotización de elección 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 el string. (No hay 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'

No hay comillas 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 tokens;

 $ 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 el sencillo, citado string.)

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

(El bucle solo se ejecuta una vez, sobre el literal entre comillas simples string.)

Expansión de comodines:

$ 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, ¡cualquiera!)

En términos más concretos, cualquier cosa que contenga un nombre de archivo normalmente debe estar entre comillas (porque los nombres de archivo pueden contener espacios en blanco y otros metacaracteres de shell). Todo lo que contenga una URL normalmente se debe citar (porque muchas URL contienen metacaracteres de shell como ? y &). Cualquier cosa que contenga una expresión regular debe estar entre comillas (ídem ídem). Todo lo que contenga espacios en blanco significativos que no sean espacios simples entre caracteres que no sean espacios en blanco debe ser citado (porque de lo contrario, el shell dividirá el espacio en blanco en espacios simples, efectivamente, y recortará cualquier espacio en blanco inicial o final).

Cuando sabe que una variable solo puede contener un valor que no contenga metacaracteres de shell, las comillas son opcionales. Por lo tanto, un no citado $? está básicamente bien, porque esta variable solo puede contener un solo número. Sin embargo, "$?" también es correcta y se recomienda por su coherencia y corrección general (aunque esta es mi recomendación personal, no una política ampliamente reconocida).

Los valores que no son variables siguen básicamente las mismas reglas, aunque también puede escapar de los metacaracteres en lugar de citarlos. Para un ejemplo común, una URL con un & en él será analizado por el shell como un comando en segundo plano a menos que el metacarácter se escape o se cite:

$ 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). static string, las comillas simples tienen más sentido, aunque cualquier forma de citar o escapar 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 “cotización 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 juntos espalda con espalda, formando un solo largo string después de la tokenización y la eliminación de cotizaciones.

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

Por otro lado, los scripts generalmente no deben usar ls por nada. Para expandir un comodín, simplemente ... utilícelo.

$ printf '%sn' $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: %sn' "$file"
> done
Found file: file1.txt
Found file: file_other.txt

(El bucle es completamente superfluo en el último ejemplo; printf específicamente funciona bien con múltiples argumentos. stat también. Pero recorrer una coincidencia de comodines es un problema común y, con frecuencia, se realiza de manera incorrecta).

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 lo abreviamos para "citar todo a menos que sepa exactamente lo que está haciendo".

Aquí hay una fórmula de tres puntos para cotizaciones en general:

Doble comillas

En contextos en los que queremos suprimir la división y el agrupamiento de palabras. También en contextos donde queremos que el literal sea tratado como un string, no una expresión regular.

Comillas simples

En string 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 globbing o quiero división de palabras y globbing.


Ejemplos de

Doble comillas

  • cadenas literales con espacios en blanco ("StackOverflow rocks!", "Steve's Apple")
  • expansiones variables ("$var", "$arr[@]")
  • sustituciones de mando"$(ls)", "`ls`")
  • globs donde la ruta del directorio o la parte del nombre del archivo incluye espacios ("/my dir/"*)
  • para proteger las comillas simples"single'quote'delimited'string")
  • Expansión del parámetro 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"')
  • regex literales que necesitan interpolación para ser suprimidos
  • use comillas de shell para literales que involucren caracteres especiales ($'nt')
  • use las comillas de shell donde 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 [[ ]] Expresión libre de problemas de división de palabras y globbing (esto es una cuestión de estilo y las opiniones pueden variar ampliamente)
  • donde queremos dividir palabrasfor word in $words)
  • donde queremos globbingfor txtfile in *.txt; do ...)
  • donde queremos ~ para ser interpretado como $HOME (~/"some dir" pero no "~/some dir")

Ver también:

  • Diferencia entre comillas simples y dobles en Bash
  • ¿Cuáles son las variables especiales de caparazón del signo de dólar?
  • Citas y escape - Bash Hackers 'Wiki
  • ¿Cuándo es necesaria la doble cotización?

Puntuaciones y comentarios

Eres capaz de amparar nuestro análisis fijando un comentario y dejando una valoración te lo agradecemos.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *