Aqui documentos como várias linhas de comando dentro do bash

3

Eu criei um trecho para testar o documento aqui

$ cat test101.sh
ls
$ bash test101.sh
bmdt.md       brmdh.md  fild.md  test     test101.sh  test2  test5  testfile
breakfast.md  exec  file.md  test.sh  test12      test3  test7

Chega aqui ao documento

$ $(cat << EOF
→ ls
→ EOF)
bmdt.md       brmdh.md  fild.md  test     test101.sh  test2  test5  testfile
breakfast.md  exec  file.md  test.sh  test12      test3  test7

Funciona corretamente,
Infelizmente, não é o caso do comando estruturado

$ $(cat << EOF
→ for i in *
→ do 
→   stat $i
→ done
→ EOF)
-bash: for: command not found

Eu tentei alternadamente

$ bash $(cat << EOF
→ for i in *
→ do
→   stat $i
→ done
→ EOF)
bash: for: No such file or directory

Qual é o problema de não permitir o comando for?

    
por avirate 28.10.2018 / 15:04

1 resposta

5

Um documento aqui é uma forma de redirecionamento. Em seus comandos, você redireciona para o comando cat e, em seguida, tenta usar a saída como um comando em uma substituição de comando.

  1. $i será expandido quando o conteúdo do documento here for formado. Isso acontece muito antes de o loop no documento ser executado. Se a variável i não estiver definida, ela será expandida para uma sequência vazia. Você pode optar por citar o documento here (citando o primeiro EOF como 'EOF' ou \EOF ) para que nenhuma expansão seja feita nele ou para explicitamente escapar do $ as \$ para protegê-lo da expansão.
  2. O conteúdo do documento here será interpretado como uma única string com linhas delimitadas de nova linha. Ele não passará pelo reconhecimento usual de token e por outras etapas envolvidas na análise de comandos comuns, mas será dividido em palavras individuais, pois a substituição do comando não é citada. Em particular, for não será reconhecido como uma palavra-chave do shell. É por isso que seu primeiro exemplo falho falha. Para reavaliar a string, você teria que eval it, que iria reavaliar a string como a shell teria feito se tivesse sido dada na linha de comando.
  3. O último exemplo seria expandido para bash seguido por várias palavras. A primeira palavra é for , portanto, bash esperaria executar um script chamado for no diretório atual, mas falha ao fazer isso.

  4. Em todos os exemplos, bash deve também ter reclamado que o documento here não foi terminado corretamente (desde que a última linha é EOF) com um parêntese direito à direita, não EOF ) , dizendo algo como

    bash: warning: here-document at line 1 delimited by end-of-file (wanted 'EOF')
    

    a menos que você esteja usando uma versão bash mais antiga, como a padrão no macOS.

Em vez disso, essa seria uma melhor escolha de ações, pois evita a conversão de código em uma string que precisa ser reinterpretada e, em vez disso, fornece o documento como um script de shell diretamente para um interpretador de shell.

bash <<'END_SCRIPT'
for i in *; do
    printf 'Filename: "%s"\n' "$i"
done
END_SCRIPT

O primeiro dos seus exemplos funciona porque é um comando simples.

    
por 28.10.2018 / 15:40

Tags