Algunas personas tienen esa noción errónea de que reades el comando de leer una línea. No es.
readlee palabras de una línea (posiblemente barra invertida), donde las palabras están $IFSdelimitadas y la barra invertida puede usarse para escapar de los delimitadores (o líneas continuas).
La sintaxis genérica es:
read word1 word2... remaining_words
readlee la entrada estándar de un byte a la vez hasta que encuentra un carácter de nueva línea sin escape (o al final de la entrada), se divide que de acuerdo con las reglas complejas y almacena el resultado de esa división en $word1, $word2... $remaining_words.
Por ejemplo en una entrada como:
<tab> foo bar\ baz bl\ah blah\
whatever whatever
y con el valor predeterminado de $IFS, read a b casignaría:
$a ⇐ foo
$b ⇐ bar baz
$c ⇐ blah blahwhatever whatever
Ahora, si se pasa solo un argumento, ese no se convierte read line. Aun esta read remaining_words. El procesamiento de barra invertida todavía se realiza, los caracteres de espacio en blanco IFS aún se eliminan desde el principio y el final.
La -ropción elimina el procesamiento de la barra diagonal inversa. Entonces, el mismo comando anterior con en -rsu lugar asignaría
$a ⇐ foo
$b ⇐ bar\
$c ⇐ baz bl\ah blah\
Ahora, para la parte de división, es importante darse cuenta de que hay dos clases de caracteres para $IFS: los caracteres de espacio en blanco IFS (a saber, espacio y tabulación (y nueva línea, aunque aquí eso no importa a menos que use -d), que también sucede estar en el valor predeterminado de $IFS) y los demás. El tratamiento para esas dos clases de personajes es diferente.
Con IFS=:( :no siendo un carácter de espacio en blanco IFS), al igual que una entrada :foo::bar::se divide en "", "foo", "", bary ""(y un extra ""con algunas implementaciones, aunque eso no importa a excepción de read -a). Mientras que si reemplazamos eso :con espacio, la división se realiza solo en fooy bar. Eso es líder y los posteriores se ignoran, y sus secuencias se tratan como una sola. Hay reglas adicionales cuando se combinan los espacios en blanco y los no espacios en blanco $IFS. Algunas implementaciones pueden agregar / eliminar el tratamiento especial duplicando los caracteres en IFS ( IFS=::o IFS=' ').
Entonces, aquí, si no queremos que se eliminen los caracteres de espacio en blanco sin escape iniciales y finales, debemos eliminar esos caracteres de espacio en blanco IFS de IFS.
Incluso con caracteres IFS que no sean espacios en blanco, si la línea de entrada contiene uno (y solo uno) de esos caracteres y es el último carácter de la línea (como IFS=: read -r worden una entrada como foo:) con shells POSIX (no zshni algunas pdkshversiones), esa entrada se considera como una foopalabra porque en esos shells, los caracteres $IFSse consideran terminadores , por wordlo que contendrán foo, no foo:.
Entonces, la forma canónica de leer una línea de entrada con el readincorporado es:
IFS= read -r line
(tenga en cuenta que para la mayoría de las readimplementaciones, eso solo funciona para líneas de texto ya que el carácter NUL no es compatible, excepto en zsh).
El uso de la var=value cmdsintaxis asegura que IFSsolo se configure de manera diferente durante la duración de ese cmdcomando.
Nota de la historia
La readconstrucción fue introducida por el shell Bourne y ya era para leer palabras , no líneas. Hay algunas diferencias importantes con los modernos proyectiles POSIX.
El shell Bourne readno admitía una -ropción (que fue introducida por el shell Korn), por lo que no hay forma de deshabilitar el procesamiento de barra diagonal inversa que no sea el preprocesamiento de la entrada con algo como sed 's/\\/&&/g'eso.
El shell Bourne no tenía esa noción de dos clases de caracteres (que nuevamente fue presentada por ksh). En el shell Bourne todos los caracteres se someten al mismo tratamiento que los espacios en blanco IFS pueden hacer en ksh, es decir IFS=: read a b cen una entrada como foo::barasignaría bara $b, no la cadena vacía.
En el shell Bourne, con:
var=value cmd
Si cmdestá integrado (como reades), varpermanece configurado valuedespués de que cmdhaya terminado. Eso es particularmente crítico $IFSporque, en el shell Bourne, $IFSse usa para dividir todo, no solo las expansiones. Además, si elimina el carácter de espacio $IFSen el shell Bourne, "$@"ya no funciona.
En el shell Bourne, la redirección de un comando compuesto hace que se ejecute en un subshell (en las versiones más antiguas, incluso cosas como read var < fileo exec 3< file; read var <&3no funcionaban), por lo que era raro en el shell Bourne usar readcualquier cosa que no fuera la entrada del usuario en el terminal (donde el manejo de continuación de línea tenía sentido)
Algunos Unices (como HP / UX, también hay uno util-linux) todavía tienen un linecomando para leer una línea de entrada (que solía ser un comando estándar de UNIX hasta la versión 2 de la especificación UNIX única ).
Eso es básicamente lo mismo, head -n 1excepto que lee un byte a la vez para asegurarse de que no lea más de una línea. En esos sistemas, puede hacer:
line=`line`
Por supuesto, eso significa generar un nuevo proceso, ejecutar un comando y leer su salida a través de una tubería, por lo que es mucho menos eficiente que el de ksh IFS= read -r line, pero aún mucho más intuitivo.