Ya es hora de resolver este enigma que me ha estado molestando durante años ...
Me he encontrado con esto de vez en cuando y pensé que este es el camino a seguir:
$(comm "$(arg)")
Y pensé que mi punto de vista estaba fuertemente respaldado por la experiencia. Pero ya no estoy tan seguro. Shellcheck tampoco puede decidirse . Son ambos:
"$(dirname $0)"/stop.bash
^-- SC2086: Double quote to prevent globbing and word splitting.
Y:
$(dirname "$0")/stop.bash
^-- SC2046: Quote this to prevent word splitting.
¿Cuál es la lógica detrás?
(Es Shellcheck versión 0.4.4, por cierto).
bash
quoting
command-substitution
Tomász
fuente
fuente
"$(dirname "$0")"/stop.bash
? Parece funcionar ... ¿Cuál es la historia?shell_level_1 $(shell_level_2) shell_level_1
cuando está dentro del$(....)
, ingresa un "subnivel" de shell, PERO puede escribir en él como si estuviera en el nivel primario (es decir, puede escribir directamente en"
lugar de\"
, etc.). ej .:touch "/tmp/a file" ; echo "its size is: $(find "/tmp/a file" -ls | awk '{print $5}) ..." : if you used backticks you'd have to
encontrar \ "/ tmp / un archivo \" `yprint \$5
. Sin$(...)
necesidad: el shell se adapta al nuevo nivel y puede escribir directamente como si su intérprete ahora también estuviera en ese nivel.Respuestas:
Necesitas usar
"$(somecmd "$file")"
.Sin las comillas, una ruta con un espacio se dividirá en el argumento
somecmd
y se dirigirá al archivo incorrecto. Entonces necesitas citas en el interior.Cualquier espacio en la salida de
somecmd
también causará división, por lo que necesita comillas en el exterior de toda la sustitución del comando.Las citas dentro de la sustitución del comando no tienen efecto en las citas fuera de ella. El propio manual de referencia de Bash no es muy claro al respecto, pero BashGuide lo menciona explícitamente . El texto en POSIX también lo requiere, ya que "cualquier script de shell válido" está permitido dentro
$(...)
:Ejemplo:
a. Sin comillas,
dirname
procesa ambos./space
yhere/foo
:si. Citas en el interior,
dirname
procesos./space here/foo
, donaciones./space here
, que se divide en dos:C. Citas en el exterior,
dirname
procesa ambos./space
yhere/foo
, sale en líneas separadas, pero ahora las dos líneas forman un solo argumento :re. Citas tanto dentro como fuera, esto da la respuesta correcta:
(eso posiblemente hubiera sido más simple si
dirname
solo procesara el primer argumento, pero eso no mostraría la diferencia entre los casos ayc).Tenga en cuenta que con
dirname
(y posiblemente otros) también necesita agregar--
, para evitar que el nombre de archivo se tome como una opción en caso de que comience con un guión, así que úselo"$(dirname -- "$file")"
.fuente
$( )
crea un nuevo contexto, por lo que las citas dentro de él son independientes de las citas fuera de él. Y generalmente quieres citas en ambos contextos.