
Tengo un script bash que valida las entradas de la tabla. El valor de salida final es $out que se inserta en una instrucción SQL INSERT que luego se agrega a /tmp/crew.txt. Si bien $out está claramente separado por comas, no hay comas entre los valores en la instrucción INSERT resultante en /tmp/crew.txt. ¿Por qué es así y cómo se puede solucionar para que tenga valores separados por comas en /tmp/crew.txt?
#!/bin/bash
out=290,'02:20:00','02:40:00',20.5,NULL
echo "${out:1}"
290,'02:20:00','02:40:00',20.5,NULL
echo "INSERT INTO tip_run (date_linkid, start_time, finish_time, weight, note) VALUES ("${out:1}");" >> /tmp/crew.txt
vi /tmp/crew.txt
INSERT INTO tip_run (date_linkid, start_time, finish_time, weight, note) VALUES ( 290 '02:20:00' '02:40:00' 20 NULL);
Por tanto, el resultado en /tmp/crew.txt debería ser:
INSERT INTO tip_run (date_linkid, start_time, finish_time, weight, note) VALUES ( 290,'02:20:00','02:40:00',20,NULL);
Respuesta1
Hipótesis: su IFS
variable contiene ,
. El script no cambia IFS
, por lo que el valor no predeterminado debe haber estado en el entorno.
esta otra respuestaNoté que no has entrecomillado ${out:1}
en una línea que se parece a esta:
echo "foo"${out:1}"bar"
Variable sin comillasse somete a división de palabras y generación de nombres de archivos. La división de palabras se realiza por IFS
. Lo que no está entre comillas ${out:1}
se divide en varias palabras, echo
obtiene múltiples argumentos y los imprime separados por espacios simples (porque esto es lo que echo
hace, sin importar el IFS
).
si usasteprintf
según lo aconsejado, sería más fácil saber si la variable está entre comillas:
printf 'INSERT INTO tip_run (date_linkid, start_time, finish_time, weight, note) VALUES (%s);\n' "${out:1}"
Y si no comillas dos veces la variable, printf
obtendrías múltiples argumentos ${out:1}
y generarías múltiples líneas. Entonces debería ser bastante obvio que se produce alguna división. El uso echo
de esa concatenación de argumentos ofuscó este hecho hasta cierto punto.
Cuestiones separadas:
El resultado deseado sugiere que no lo desea,
"${out:1}"
pero" $out"
con un espacio inicial.Para incluir comillas simples en la variable, debe asegurarse de que el shell no las elimine. Escapa de ellos (créditos alrespuesta ya mencionada) o entrecomillarlos dos veces:
out="290,'02:20:00','02:40:00',20.5,NULL"
Respuesta2
¿Por qué es así y cómo se puede solucionar?
Al eliminar la salida repetida y las líneas en blanco de su secuencia de comandos, se obtiene la siguiente secuencia de comandos limpia:
#!/bin/bash
out=290,'02:20:00','02:40:00',20.5,NULL
echo "${out:1}"
echo "INSERT INTO tip_run (date_linkid, start_time, finish_time, weight, note) VALUES ("${out:1}");" >> /tmp/crew.txt
Ejecutando ese script aunqueShellCheck: herramienta de análisis de scripts de shellproduce el siguiente error:
$ shellcheck myscript
Line 4:
echo "INSERT INTO tip_run (date_linkid, start_time, finish_time, weight, note) VALUES ("${out:1}");" >> /tmp/crew.txt
>> ^-- SC2027: The surrounding quotes actually unquote this. Remove or escape them.
$
Eliminar las comillas como se sugiere corrige ese error, por lo que ahora tenemos:
#!/bin/bash
out=290,'02:20:00','02:40:00',20.5,NULL
echo "${out:1}"
echo "INSERT INTO tip_run (date_linkid, start_time, finish_time, weight, note) VALUES (${out:1});" >> /tmp/crew.txt
Sin embargo, ejecutar esto todavía no da la respuesta correcta, ya que echo "${out:1}"
muestra que las comillas simples '
no se almacenan out
y será necesario escaparlas:
$ test.sh
90,02:20:00,02:40:00,20.5,NULL
$
Arreglar esto da:
#!/bin/bash
out=290,\'02:20:00\',\'02:40:00\',20.5,NULL
echo "${out:1}"
echo "INSERT INTO tip_run (date_linkid, start_time, finish_time, weight, note) VALUES (${out:1});" >> test.txt
Tenga en cuenta que he cambiado el nombre del archivo de salida atest.txt
Pruebas:
$ test.sh
90,'02:20:00','02:40:00',20.5,NULL
$ cat test.txt
INSERT INTO tip_run (date_linkid, start_time, finish_time, weight, note) VALUES (90,'02:20:00','02:40:00',20.5,NULL);
$
Entonces la versión final fija de su script es:
#!/bin/bash
out=290,\'02:20:00\',\'02:40:00\',20.5,NULL
echo "${out:1}"
echo "INSERT INTO tip_run (date_linkid, start_time, finish_time, weight, note) VALUES (${out:1});" >> >> /tmp/crew.txt
Aquí termina la lección sobre cómo depurar su script roto.
Respuesta3
La solución que me funciona es hacer eco de la siguiente declaración INSERT:
echo "INSERT INTO tip_run (date_linkid, start_time, finish_time, weight, note) VALUES (${out:1});" >> /tmp/crew.txt
No es necesario escapar. Sin embargo, no estoy seguro del por qué.