¿Por qué no puede invertir el orden del operador de redirección de entrada para los bucles while?

11

En Bash puede mover los operadores de redirección de entrada al frente de un comando:

cat <<< "hello"
# equivalent to
<<< "hello" cat

¿Por qué no puedes hacer lo mismo para los bucles while?

while read -r line; do echo "$line"; done <<< "hello"
# hello

<<< "hello" while read -r line; do echo "$line"; done
# -bash: syntax error near unexpected token `do'

Me resulta un poco confuso ya que puedes conectarlo a un bucle while. ¿Estoy haciendo algo mal o fue solo una decisión de diseño?

philraj
fuente

Respuestas:

16

Es solo una consecuencia de cómo se define la gramática. De la especificación POSIX Shell Grammar :

command          : simple_command
                 | compound_command
                 | compound_command redirect_list
                 | function_definition
                 ;

Y:

simple_command   : cmd_prefix cmd_word cmd_suffix
                 | cmd_prefix cmd_word
                 | cmd_prefix
                 | cmd_name cmd_suffix
                 | cmd_name
                 ;
[...]
cmd_prefix       :            io_redirect
                 | cmd_prefix io_redirect
                 |            ASSIGNMENT_WORD
                 | cmd_prefix ASSIGNMENT_WORD
                 ;
cmd_suffix       :            io_redirect
                 | cmd_suffix io_redirect
                 |            WORD
                 | cmd_suffix WORD
                 ;

Como puede ver, con comandos compuestos, la redirección solo se permite después , pero con comandos simples, también se permite antes. Entonces, cuando el shell ve <redirection> foo, foose trata como un comando simple, no como un comando compuesto, y whileya no se trata como una palabra clave:

$ < foo while
bash: while: command not found

Por lo tanto, does inesperado, ya que solo se permite después de ciertas palabras clave.

Entonces, esto se aplica no solo a los whilebucles, sino a la mayoría de las formas de configurar comandos compuestos usando palabras reservadas:

$ < foo {
bash: {: command not found
$ < foo if
bash: if: command not found
$ < foo for
bash: for: command not found
muru
fuente
Buena explicación, gracias.
philraj