Estoy leyendo un par de libros sobre scripts de bash y me cuesta entender las citas adecuadas y el uso de IFS
. Quizás alguien pueda ayudarme con un pequeño ejemplo que involucra nombres de archivo con comillas. Al hacer esto desde una línea de comando, esto funciona para imprimir los nombres de archivo correctamente, incluso si incluyen espacios:
set - *
for i in "$@"; do echo $i; done
Esto no funciona, ya que se rompe en los espacios:
set - `find . -name "*"`
for i in "$@"; do echo $i; done
Ni tampoco:
IFS=$'\0' set - `find . -name "*" -print0`
for i in "$@"; do echo $i; done
Tampoco la combinación que usa IFS=$'\n'
y -print
. ¿Por qué fallan todos estos?
Lo siguiente también falla, pero en este caso se produce un error ("bash: error de sintaxis cerca del token inesperado` do '"). ¿Por qué?
IFS=$'\n' for i in `find . -name "*" -type f`; do echo $i; done
pero esto funciona (observe el ";"):
IFS=$'\n'; for i in `find . -name "*" -type f`; do echo $i; done
y esto falla porque los nombres de archivo no se dividen en absoluto (los for
bucles solo una vez):
IFS=''; for i in `find . -name "*" -type f -print0`; do echo -e "$i\n"; done
Entonces, de nuevo, ¿por qué fallan el primero y el tercero?
Finalmente, ¿estoy en lo cierto al creer que, al configurar IFS
, ''
es lo mismo que $'\0'
? (Probé ambos en el ejemplo anterior). Si es así, ¿por qué aparentemente necesito en $'\n'
lugar de solo \n
?
* Bash es la versión 4.3.42 (1) en Ubuntu Gnome 16.04.
fuente
IFS=$'\n' set -
encontrar. -name "*" -print`` yfor i in "$@"; do echo $i; done
. Definitivamente no funciona.;
después delIFS=...
yo no. Es como el segundo caso en el segundo grupo de 3. La pregunta es, ¿por qué es necesario? Espero que sin el;
, la modificación de la variable sea temporal, dentro del siguiente comando. No quiero que sea permanente.IFS=$'\n'; set - `find`;
trabajar pero noIFS=$'\n' set - `find`;
. Una explicación plausible es que enIFS=$'\n' set - `find`;
,find
se sustituye y se tokeniza con IFS actual antes deset
ejecutarse.Respuestas:
Dos cosas que aprendí al depurar comandos bash: una) Si no funciona como cree que debería, repita los comandos para asegurarse de que se muestren de la manera que usted cree que deberían hacerlo. Dos) Ejecute manualmente los comandos que tiene dentro de sus comandos para ver si se ejecutan correctamente (a menos que sean comandos potencialmente destructivos, como: rm, dd, chmod 777, etc.).
¿Cómo o qué estás tratando de lograr exactamente? El mío parece funcionar bien con ese comando al pie de la letra, por lo que deberás explicar lo que quieres que haga. ¿Tiene espacios en sus nombres de archivo que están causando problemas con su comando? En tanto que a deshacerse del espacio de la variable IFS, es probable que funcione de la manera deseada:
IFS=$'\n\t'
. La-print0
opción básicamente elimina todos los separadores de línea, por lo que todo lo que desee de esos comandos no tiene separadores a menos que los archivos tengan espacios en sus nombres. Para su segunda serie de preguntas:Este comando no se ejecuta correctamente porque bash lo lee así:
La primera línea establece IFS a:
$'\n' for i in
. Después de eso, la siguiente línea se lee como:,do echo $i
que no funciona ya que eldo
comando requiere un ciclo de algún tipo para ser el comando anterior. El siguiente funciona porque el punto y coma le dice a bash que se ha alcanzado el final del comando, por lo que:Sí a la primera parte,
''
y'\0'
ambos se consideran NULL, por lo que son básicamente lo mismo. Esto se debe a que bash se interpreta$''
como una cadena ANSI C. Y debe tener comillas alrededor de \ n para que bash lo interprete como una cadena C para que se coloque un carácter de nueva línea en el IFS.Puedes leer más sobre esto aquí .
fuente
set
. Estoy seguro. (2) Comprendí quevar=value <command>
debería establecersevar
temporalmente en el valor cuando se ejecuta el comando. Aquí el comando es unfor
, ¿no? (3) El último comando tiene un;
después delIFS=
, pero todavía no funciona aunque-print0
debería producir nombres de archivo separados por nulos.-print0
comando debe agregar caracteres nulos en lugar de líneas nuevas; sin embargo, bash los elimina automáticamente. Deberá guardar la salida en un archivo si desea conservarlos; Sin embargo, no estoy seguro de que esto sea lo que querrá, ya que Bash eliminará los caracteres nulos si intenta usarlos. Bash no permitirá caracteres nulos en las variables, como puede ver aquí .IFS=''
no funciona, porque no puedo configurar IFS en\0
set
, lo único que me deja perplejo es queIFS=$'\n' set - `find . -name "*" -print`
falla, rompiendo los nombres de los archivos en los espacios.find . -name "*" -print
</code> y eso debería solucionar su problema.