¿Por qué usar comillas dobles en una prueba [[]]?

23

Digamos que tenemos 2 enteros en un script bash:

value1=5
value2=3

Entonces, ¿por qué necesitamos usar comillas dobles en caso de una prueba? Por ejemplo:

if [[ "$value1" -eq "$value2" ]]

¿Por qué no solo usar lo siguiente?

if [[ $value1 -eq $value2 ]]

Para mí, las comillas dobles no tienen ningún sentido.

Suricata
fuente
55
Citando en la cáscara tiene poco que ver con cuerdas realidad se trata de la prevención de la cáscara de la realización de la división de palabras (como en los tipos de datos.) (Y otros tipos de expansiones.)
filbranden
13
Si bien, como señaló Terdon, no es necesario también citar variables en este constructo específico (y, por supuesto, con valores de una palabra en cualquier lugar), me gustaría darle el consejo para citar siempre sus variables. ¿Realmente sabes en qué contextos puedes dejar variables sin comillas? La razón para cotizar en absoluto, incluso si no es necesario con 5y 3, es la mantenibilidad. Los valores pueden cambiar más tarde y los errores resultantes pueden no ser obvios.
Peter - Restablece a Mónica
2
@sudodus No creo que sea cierto para [[ ]], solo para [ ].
Benjamin W.
1
Tienes razón, @BenjaminW. La división de palabras no es el único caso por el que es una buena idea usar comillas dobles para las variables. También existe el caso cuando una variable está en blanco. Eso hará que la declaración en [] falle (por ejemplo, [2 -eq] con un error, pero [[]] no es vulnerable (como en el caso de la división de palabras).
sudodus
2
@marcelm, Bash, ksh y Zsh tienen variables enteras, y dentro de [[ ]]ellas también obligan a los operandos -eqa enteros.
ilkkachu

Respuestas:

7

Palabra dividida.

Este ejemplo es muy improbable, pero posible , así que si quieres codificar defensivamente, cubre tus pistas con comillas:

$ set -x
$ value1=5
+ value1=5
$ value2=3
+ value2=3
$ [ $value1 -eq $value2 ]
+ '[' 5 -eq 3 ']'

OK, todo bien hasta ahora. Arrojemos la llave a los engranajes:

$ IFS=456
+ IFS=456
$ [ $value1 -eq $value2 ]
+ '[' '' -eq 3 ']'
bash: [: : integer expression expected

Ups

$ [ "$value1" -eq "$value2" ]
+ '[' 5 -eq 3 ']'

Ahh

Glenn Jackman
fuente
2
Pero OP usa corchetes dobles, por lo que no se divide la palabra.
user000001
55
Sí, esto no es realmente relevante para la [[ ]]construcción de bash .
terdon
1
Eh? [ $value1 -eq $value2 ]con un vacío value1sería '[' -eq 3 ']'sin un ''en el lado izquierdo.
Charles Duffy
También me sorprendió, pero ahí está la evidencia.
Glenn Jackman
1
Esta respuesta no se relaciona directamente con la pregunta. Me sorprende que haya sido aceptado. Establecer como wiki de la comunidad.
Glenn Jackman
35

Realmente no necesitas las citas aquí. Este es uno de los pocos casos en los que es seguro usar una variable sin comillas. Puede confirmar esto con set -x:

$ var1=""
$ var2="3"
$ set -x
$ if [[ $var1 -eq $var2 ]]; then echo "match!"; else echo "no match!"; fi
+ [[ '' -eq 3 ]]
+ echo 'no match!'
no match!
$ if [[ "$var1" -eq "$var2" ]]; then echo "match!"; else echo "no match!"; fi
+ [[ '' -eq 3 ]]
+ echo 'no match!'
no match!

Como puede ver arriba, bash resuelve las versiones citadas y no citadas de la prueba. Lo mismo debería ser cierto para zshy, creo, cualquier otro shell que admita el [[ ]]operador.

Tenga en cuenta que este no es el caso con los más portátiles [ ]:

$ if [ $var1 -eq $var2 ]; then echo "match!"; else echo "no match!"; fi
+ '[' -eq 3 ']'
sh: [: -eq: unary operator expected
+ echo 'no match!'
no match!

El [ ]constructo, a diferencia del anterior [[ ]], requiere una cita.


Algunos enlaces útiles para obtener más información sobre cuándo y por qué se requiere una cita:

terdon
fuente
En este caso con variables enteras, sería mejor declararlas como tales. declare -i var1=es 0cuando se evalúa.
Freddy
44
Tenga en cuenta que -eqes una comparación aritmética , por lo que incluso puede dejar $fuera (dentro [[ .. ]]) y escribir [[ a -eq b ]]. Con la comparación de cadenas, necesita $, por supuesto, así que[[ $a = $b ]]
ilkkachu
2
@ user000001 buen punto. Aunque, por supuesto, es muy posible que desee expandirlos. Por ejemplo, me gustaría que esto sea un partido: var1="afoob"; var2="a*b"; [[ $var1 = $var2 ]] && echo match. Si desea utilizar los caracteres glob sin que actúen como un glob en un contexto global (como el [[ ]]), entonces necesita citar, sí.
terdon
3
@ilkkachu, eso me sorprende. Pensé que las variables "desnudas" solo se considerarían dentro de un subíndice de matriz o ((...))o $((...). Parece funcionar, pero (viejo gruñón, habilítelo) No me gusta.
Glenn Jackman
1
@glennjackman, bueno, lamento ser quien te diga eso, pero sí, los operandos -eqy los amigos en el interior también [[ ]]son contextos aritméticos. :) (Relacionado: Expansión variable automática dentro del comando bash [[]] )
ilkkachu
17

Aunque las comillas dobles no son necesarias, las razones para usarlas son:

  • Buena práctica / hábito: en este caso no son necesarios, pero en general las comillas dobles son para evitar la división accidental de palabras.
  • Porque value1y value2son variables, y es posible que no sepas lo que contienen. De lo contrario, podría preguntar: "¿Por qué molestarse con las variables en lugar de verificar if [[ 5 -eq 3 ]]? O ifir más allá, ¿por qué molestarse con el cuando ya sabes que 5 no es igual a 3? A menudo es mejor estar a la defensiva. (Es cierto esa palabra de división no va a ocurrir en [[, pero los casos en que la palabra de división no no suceden son raros. Una vez más, ver el primer punto.)
jamesdlin
fuente
1

No está directamente relacionado con tu pregunta, pero yo uso

if (($ valor1 == $ valor2)); luego

cuando comparo números pero allí tampoco tienes que usar comillas.

framp
fuente
2
if (( value1 == value2 )); then. En contextos aritméticos, ni siquiera necesita el $. Sin embargo, esta pregunta parece centrarse en las variables utilizadas en las [[ ... ]]pruebas.
Kusalananda
1
Lo sé. Pero, francamente, no uso esta función porque quiero que mis nombres de variables sean consistentes y, por lo tanto, use $ como prefijo todo el tiempo.
Fram
1

¡Tienes toda la razón!

La cita entre corchetes dobles no tiene ningún sentido, al menos en este caso.

Pero dado que uso comillas dobles a diario, especialmente para expresiones de corchetes simples, pasando argumentos a funciones y scripts, así como a veces asignación de variables (lo cual es completamente inútil para delicaciones simples), supongo que algunas personas, al menos lo hago, escribir comillas dobles alrededor de expansiones variables instintivamente .

La doble cita puede darle una sensación de seguridad. Es como volver a casa donde están las comillas dobles. - D. Kummer

Un beneficio de hacer comillas dobles en consecuencia y de manera comprensible , pero solo porque tiene sentido, es que los compañeros de trabajo que son nuevos en bash pueden aprender a escribir guiones más estables . También acentúa el hecho de que el arte del procesamiento de datos con bash se trata más de separar las secuencias de datos (incluidas las variables) mediante separadores de campo y canalizarlos a través de filtros . ¡Tan pronto como separe sus fragmentos de datos de la transmisión, manténgalos juntos con comillas dobles!

Otro beneficio podría ser la mejor legibilidad de los scripts de bash con cadenas entre comillas dobles dentro de un editor de resaltado de código .

Dominik Kummer
fuente