これはbashの複数行コマンドで記録されます。

これはbashの複数行コマンドで記録されます。

ここでドキュメントをテストするためにスニペットを作成しました。

$ 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

ここに来る文書

$ $(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

うまく動作します
が、残念ながら構造化されたコマンドの場合はそうではありません。

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

私は前に試しました

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

forコマンドが機能しない問題は何ですか?

答え1

ここでの文書化はリダイレクトの一形態です。コマンドからcatそのコマンドにリダイレクトし、出力をコマンド置換コマンドとして使用しようとしています。

  1. $iこの文書は、内容が具体化されると拡張されます。これは、ドキュメントのループが実際に実行されるずっと前に発生します。i変数が設定されていない場合は空の文字列に展開されます。拡張が実行されないように、この文書を引用するか(最初の項目EOF'EOF'またはとして引用する)、拡張を防ぐために明示的にエスケープすることを選択できます。\EOF$\$
  2. ここのドキュメントの内容は、改行で区切られた単一の文字列として解釈されます。一般的なトークン認識と一般的なコマンドの構文解析に関連する他のステップを経ることはありませんが、コマンドの置き換えが引用されていないので、別の単語に分割されます。特にforシェルキーワードとして認識されません。これが最初の失敗した例が失敗した理由です。文字列を再評価するには、evalこれを行う必要があります。これにより、文字列がコマンドラインに与えられたときにシェルが行うように文字列を再評価します。
  3. 最後の例は、bash多くの単語が続くように拡張されています。最初の単語は現在のディレクトリから呼び出されるシェルスクリプトを実行すると予想しますforが、そうしません。bashfor

  4. すべての例では、bash しなければならないまた、ここの文書が適切に終了しないと文句を言います(最後の行に閉じEOF)括弧があるためEOF)。

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

    bashmacOSのデフォルトバージョンなど、以前のバージョンを使用しない限り。

代わりに、これはコードを再解釈する必要がある文字列に変換するのを防ぎ、代わりに実行のためにシェルインタプリタに直接インラインシェルスクリプトとしてドキュメントを提供するので、より良いタスク選択になります。

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

最初の例は単純なコマンドなので動作します。

関連情報