La trampa es que
IFS=; while read..
establece IFSpara todo el entorno de shell fuera del bucle, mientras que
while IFS= read
lo redefine solo para la readinvocación (excepto en el shell Bourne). Puedes comprobar que haciendo un ciclo como
while IFS= read xxx; ... done
luego, después de tal bucle, echo "blabalbla $IFS ooooooo"imprime
blabalbla
ooooooo
mientras que después
IFS=; read xxx; ... done
las IFS estancias redefinidas: ahora echo "blabalbla $IFS ooooooo"imprime
blabalbla ooooooo
Así que si se utiliza la segunda forma, usted tiene que recordar para restablecer: IFS=$' \t\n'.
La segunda parte de esta pregunta se ha fusionado aquí , por lo que he eliminado la respuesta relacionada de aquí.
while IFS=X readno se separaX, perowhile IFS=X; readsí ...whileno tiene mucho sentido - la condición dewhileextremos en ese punto y coma, así que no hay lazo real ...readse convierte en sólo el primer comando dentro del bucle de un solo elemento o no ... ? ¿Qué pasa con eldoentonces ..?whilecondición (antesdo).IFS=el trabajo, peroIFS=Xno lo hace ... (o tal vez he sobredosis en esto durante un tiempo .. pausa para el café necesita :)Veamos un ejemplo, con un texto de entrada cuidadosamente elaborado:
Son dos líneas, la primera comienza con un espacio y termina con una barra diagonal inversa. Primero, echemos un vistazo a lo que sucede sin precauciones
read(pero utilizandoprintf '%s\n' "$text"para imprimir cuidadosamente$textsin ningún riesgo de expansión). (A continuación, se$ encuentra el indicador de comandos de la shell).readcomió las barras diagonales inversas: la barra diagonal inversa-nueva línea hace que la nueva línea se ignore, y la barra diagonal inversa-cualquier cosa ignora esa primera barra diagonal inversa. Para evitar el tratamiento especial de las barras invertidas, utilizamosread -r.Eso es mejor, tenemos dos líneas como se esperaba. Las dos líneas casi contienen el contenido deseado: el doble espacio entre
helloyworldse ha retenido, porque está dentro de lalinevariable. Por otro lado, el espacio inicial fue devorado. Esto se debe a quereadlee tantas palabras como le pasa variables, excepto que la última variable contiene el resto de la línea, pero aún comienza con la primera palabra, es decir, los espacios iniciales se descartan.Por lo tanto, para leer cada línea literalmente, debemos asegurarnos de que no haya división de palabras . Hacemos esto estableciendo la
IFSvariable en un valor vacío.Tenga en cuenta cómo establecemos
IFSespecíficamente para la duración de lareadincorporada . LosIFS= read -r lineconjuntos de la variable de entornoIFS(a un valor vacío) específicamente para la ejecución deread. Esta es una instancia de la sintaxis de comando simple general : una secuencia (posiblemente vacía) de asignaciones de variables seguida de un nombre de comando y sus argumentos (también, puede lanzar redireccionamientos en cualquier punto). Comoreades una función integrada, la variable nunca termina en el entorno de un proceso externo; no obstante, el valor de$IFSes lo que estamos asignando allí mientras sereadesté ejecutando¹. Tenga en cuenta quereadno es una función integrada especial , por lo que la asignación solo dura su duración.Por lo tanto, nos encargamos de no cambiar el valor de
IFSotras instrucciones que puedan depender de él. Este código funcionará sin importar en qué se haya configuradoIFSinicialmente el código circundante , y no causará ningún problema si el código dentro del bucle se basaIFS.Contraste con este fragmento de código, que busca archivos en una ruta separada por dos puntos. La lista de nombres de archivos se lee desde un archivo, un nombre de archivo por línea.
Si el bucle fuera
while IFS=; read -r name; do …, entoncesfor dir in $PATHno se dividiría$PATHen componentes separados por dos puntos. Si el código fueraIFS=; while read …, sería aún más obvio queIFSno está configurado:en el cuerpo del bucle.Por supuesto, sería posible restaurar el valor de
IFSdespués de ejecutarread. Pero eso requeriría conocer el valor anterior, que es un esfuerzo adicional.IFS= reades el camino simple (y, convenientemente, también el camino más corto).¹ Y, si
readse interrumpe por una señal atrapada, posiblemente mientras la trampa se está ejecutando, POSIX no lo especifica y depende del shell en la práctica.fuente
while IFS= read(sin un punto y coma después=) no es una forma especial dewhileo deIFSo deread... La construcción es genérica: es decir.anyvar=anyvalue anycommand. La falta de;después del ajusteanyvarhace que el alcance deanyvarlocales aanycommand.. El tiempo - hacer bucle / hecho es 100% no relacionada con el ámbito localany_var.Aparte de la (ya clarificada)
IFSlas diferencias de alcance entre elwhile IFS='' read,IFS=''; while readywhile IFS=''; readexpresiones idiomáticas (por mando vs script / en toda la cáscaraIFSámbito de las variables), la lección para llevar a casa es que se pierde los líderes y espacios al final de una línea de entrada si la variable IFS se establece en (contiene un) espacio.Esto puede tener consecuencias bastante graves si se procesan las rutas de archivo.
Por lo tanto, establecer la variable IFS en la cadena vacía no es una mala idea, ya que garantiza que el espacio en blanco inicial y posterior de una línea no se elimine.
Ver también: Bash, leer línea por línea desde el archivo, con IFS
fuente
Inspirado por la respuesta de Yuzem
Si quieres establecer
IFSun personaje real, esto funcionó para mífuente