Por que você não pode reverter a ordem do operador de redirecionamento de entrada por loops while?


11

No Bash, você pode mover os operadores de redirecionamento de entrada para a frente de um comando:

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

Por que você não consegue fazer o mesmo nos loops 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'

Acho um pouco confuso, já que você pode entrar em um loop while. Estou fazendo algo errado ou foi apenas uma decisão de design?

Respostas:


16

É apenas uma consequência de como a gramática é definida. Na especificação de gramática POSIX Shell :

command          : simple_command
                 | compound_command
                 | compound_command redirect_list
                 | function_definition
                 ;

E:

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 você pode ver, com comandos compostos, o redirecionamento é permitido apenas depois , mas com comandos simples, também é permitido antes. Portanto, quando o shell vê <redirection> foo, fooé tratado como um comando simples, não como um comando composto e whilenão é mais tratado como uma palavra-chave:

$ < foo while
bash: while: command not found

Portanto, o doé inesperado, pois só é permitido após determinadas palavras-chave.

Portanto, isso se aplica não apenas aos whileloops, mas à maioria das maneiras de configurar comandos compostos usando palavras reservadas:

$ < foo {
bash: {: command not found
$ < foo if
bash: if: command not found
$ < foo for
bash: for: command not found

Boa explicação, obrigado.
philraj
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.