Dlaczego nie można odwrócić kolejności operatora przekierowania wejściowego dla pętli while?


11

W Bash możesz przenieść operatory przekierowania wejścia na przód polecenia:

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

Dlaczego nie możesz zrobić tego samego dla pętli 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'

Uważam, że jest to trochę mylące, ponieważ można podłączyć do pętli while. Czy robię coś źle, czy to była tylko decyzja projektowa?

Odpowiedzi:


16

Jest to tylko konsekwencja definicji gramatyki. Ze specyfikacji gramatyki powłoki POSIX :

command          : simple_command
                 | compound_command
                 | compound_command redirect_list
                 | function_definition
                 ;

I:

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
                 ;

Jak widać, w przypadku poleceń złożonych przekierowanie jest dozwolone tylko po , ale w przypadku prostych poleceń jest również dozwolone wcześniej. Tak więc, gdy powłoka widzi <redirection> foo, foojest traktowane jako proste polecenie, a nie złożone, i whilenie jest już traktowane jako słowo kluczowe:

$ < foo while
bash: while: command not found

Dlatego dojest to nieoczekiwane, ponieważ jest dozwolone tylko po określonych słowach kluczowych.

Dotyczy to nie tylko whilepętli, ale większości sposobów konfigurowania złożonych poleceń przy użyciu słów zastrzeżonych:

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

Ładne wyjaśnienie, dziękuję.
philraj
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.