confundido acerca de las variables en bash

0

Sé que las variables en bash no tienen tipo, pero estoy confundido sobre el valor que se les asigna.

El siguiente script simple funciona bien en bash

#!/bin/bash 
tail -n +2 /cygdrive/c/workdir\ \(newco\,\ LLC\)/workfile.txt > \
/cygdrive/c/workdir\ \(newco\,\ LLC\)/workfile2.txt

Sin embargo, lo siguiente no

#!/bin/bash
tmpdir=/cygdrive/c/workdir\ \(newco\,\ LLC\)
tail -n +2 $tmpdir/workfile.txt > $tmpdir/workfile2.txt

¿Hay alguna explicación para este comportamiento?

alegre
fuente

Respuestas:

3

Debe asegurarse de citar las variables que pueden tener espacios en ellas. En su caso, tailestá recibiendo tres archivos: /cygdrive/c/workdir, (newco,y LLC)porque $tmpdirtiene tres palabras separadas por espacios.

Sé que escapaste del espacio al asignar $tmpdir, pero eso simplemente sirvió para evitar que cada palabra se interprete como un comando separado durante la asignación. Si entonces echo $tmpdir, obtendrás
/cygdrive/c/workdir (newco, LLC), y eso es a lo que se está pasando tail.

Para evitar esto, cita $tmpdir:

tail -n +2 "${tmpdir}/workfile.txt" > "${tmpdir}/workfile2.txt"
savanto
fuente
Gracias. ¿Cuál es la diferencia entre "$ {tmpdir} /workfile.txt" y "$ tmpdir / workfile.txt"?
Gappy 05 de
2
Las llaves se utilizan para garantizar el análisis adecuado de los nombres de las variables. Si tuviera una variable llamada tmp, podría hacer algo como ${tmp}dir/workfile.txtsustituirla en lugar de la completa $tmpdir(suponiendo que también exista).
gronostaj 05 de
0

Escriba la primera línea en bash y luego repita esa variable, esto es lo que verá:

$ tmpdir=/cygdrive/c/workdir\ \(newco\,\ LLC\)
$ echo $tmpdir
/cygdrive/c/workdir (newco, LLC)

Si aún no está claro cuál es el culpable, agregue echoal comienzo de su segunda línea y envuélvala entre comillas dobles. Verá qué comando se ejecuta realmente:

$ echo "tail -n +2 $tmpdir/workfile.txt > $tmpdir/workfile2.txt"
tail -n +2 /cygdrive/c/workdir (newco, LLC)/workfile.txt > /cygdrive/c/workdir (newco, LLC)/workfile2.txt

Has escapado correctamente de la asignación de variables, pero eso no es suficiente. Bash realiza una simple sustitución de subcadena, insertando espacios adicionales y rompiendo su comando.

Como @savanto sugirió en su respuesta, puede ajustar las variables entre comillas dobles para garantizar que los espacios adicionales no se traten como separadores de argumentos. Esta línea:

tail -n +2 "${tmpdir}/workfile.txt" > "${tmpdir}/workfile2.txt"

se verá así después de la sustitución de variables:

tail -n +2 "/cygdrive/c/workdir (newco, LLC)/workfile.txt" > "/cygdrive/c/workdir (newco, LLC)/workfile2.txt"

Esta es la forma más común y preferida de resolver ese problema. Si desea desesperadamente evitar las comillas dobles, puede intentar el doble escape: primero al asignar, luego después de la sustitución.

$ tmpdir=/cygdrive/c/workdir\\\ \\\(newco\\\,\\\ LLC\\\)
$ echo $tmpdir
/cygdrive/c/workdir\ \(newco\,\ LLC\)

Explicación rápida de las barras invertidas triples: una barra invertida significa: "tratar el siguiente carácter como un carácter normal, ignorar cualquier significado especial" (es decir, escapar de él ). La primera barra diagonal inversa es un carácter de escape, por lo que la segunda se tratará como un carácter de barra diagonal inversa, no como un carácter de escape. Por lo tanto, la doble barra invertida produce una sola barra invertida. El tercero simplemente escapa al siguiente personaje, como el espacio o el paréntesis. Por ejemplo a\\\ bse convertirá a\ b.

Ahora, si sustituimos variables en su comando, se escapará correctamente:

tail -n +2 /cygdrive/c/workdir\ \(newco\,\ LLC\)/workfile.txt > /cygdrive/c/workdir\ \(newco\,\ LLC\)/workfile2.txt
gronostaj
fuente