Una forma común de hacer cosas con un par de archivos es, y no me pegue por eso:
for f in $(ls); do …
Ahora, para estar a salvo de archivos con espacios u otros caracteres extraños, una forma ingenua sería hacer:
find . -type f -print0 | while IFS= read -r -d '' file; …
Aquí, la -d ''
abreviatura es para configurar el ASCII NUL como en -d $'\0'
.
¿Pero por qué es así? ¿Por qué son ''
y $'\0'
lo mismo? ¿Se debe a que las raíces C de Bash con una cadena vacía siempre están terminadas en nulo?
for f in *
lugar de analizarls
.for i in $(ls)
es terriblemente estúpido, estoy casi avergonzado de haberlo usado como un mal ejemplo aquí.find … -exec
lugar de recorrer los archivos, lo que funciona para la mayoría de los casos en los que usaría un bucle for. Aquí,find
se encarga de todo por ti.Respuestas:
Las
man page of bash
lecturas:Debido a que las cadenas generalmente terminan en nulo, el primer carácter de una cadena vacía es el byte nulo. - Tiene sentido para mi. :)
La fuente lee:
Para una cadena vacía
delim
es simplemente el byte nulo.fuente
split()
se dividirá entre cada carácter. Sospecho que "por razones históricas" puede ser la mejor explicación que podamos obtener.'\0'
con'X\0'
debe darle'X\0'
, si el derecho de hacer. Esto no tiene mucho que ver con funciones de alto nivel en lenguajes como JavaScript @dondelim = *list_optarg;
deja en claro por qué es así.''
y$'\0'
lo mismo?", Michas dio la explicación inmediata de "eso es lo que hace el código". Esbocé una forma alternativa de manejar la cadena vacía que vi como igualmente razonable y sugerí que elegir una u otra era simplemente una cuestión de convención o casualidad.Hay dos deficiencias en bash que se compensan entre sí.
Cuando escribe
$'\0'
, eso se trata internamente de manera idéntica a la cadena vacía. Por ejemplo:Esto se debe a que internamente bash almacena todas las cadenas como cadenas C , que tienen terminación nula: un byte nulo marca el final de la cadena. Bash trunca silenciosamente la cadena al primer byte nulo (¡que no es parte de la cadena!).
Cuando pasa una cadena como argumento a la
-d
opción de laread
construcción, bash solo mira el primer byte de la cadena. Pero en realidad no verifica que la cadena no esté vacía. Internamente, una cadena vacía se representa como una matriz de bytes de 1 elemento que contiene solo un byte nulo. Entonces, en lugar de leer el primer byte de la cadena, bash lee este byte nulo.Luego, internamente, la maquinaria detrás de la construcción
read
funciona bien con bytes nulos; sigue leyendo byte a byte hasta que encuentra el delimitador.Otras conchas se comportan de manera diferente. Por ejemplo, ash y ksh ignoran los bytes nulos cuando leen la entrada. Con ksh,
ksh -d ""
lee hasta una nueva línea. Los shells están diseñados para hacer frente bien al texto, no a los datos binarios. Zsh es una excepción: utiliza una representación de cadena que hace frente a bytes arbitrarios, incluidos los bytes nulos; en zsh,$'\0'
es una cadena de longitud 1 (peroread -d ''
, curiosamente, se comporta comoread -d $'\0'
).fuente
read
cambiado en bash 4.3 para que ahora omita bytes nulos. Por ejemplo,read x< <(printf a\\0a)
establecex
enaa
lugar dea
.