La variable de script Bash con valores separados por comas no está separada por comas cuando se agrega a un archivo diferente

La variable de script Bash con valores separados por comas no está separada por comas cuando se agrega a un archivo diferente

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 IFSvariable 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, echoobtiene múltiples argumentos y los imprime separados por espacios simples (porque esto es lo que echohace, 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, printfobtendrí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 echode 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 outy 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é.

información relacionada