ここでドキュメントをテストするためにスニペットを作成しました。
$ 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
そのコマンドにリダイレクトし、出力をコマンド置換コマンドとして使用しようとしています。
$i
この文書は、内容が具体化されると拡張されます。これは、ドキュメントのループが実際に実行されるずっと前に発生します。i
変数が設定されていない場合は空の文字列に展開されます。拡張が実行されないように、この文書を引用するか(最初の項目EOF
を'EOF'
またはとして引用する)、拡張を防ぐために明示的にエスケープすることを選択できます。\EOF
$
\$
- ここのドキュメントの内容は、改行で区切られた単一の文字列として解釈されます。一般的なトークン認識と一般的なコマンドの構文解析に関連する他のステップを経ることはありませんが、コマンドの置き換えが引用されていないので、別の単語に分割されます。特に
for
シェルキーワードとして認識されません。これが最初の失敗した例が失敗した理由です。文字列を再評価するには、eval
これを行う必要があります。これにより、文字列がコマンドラインに与えられたときにシェルが行うように文字列を再評価します。 最後の例は、
bash
多くの単語が続くように拡張されています。最初の単語は現在のディレクトリから呼び出されるシェルスクリプトを実行すると予想しますfor
が、そうしません。bash
for
すべての例では、
bash
しなければならないまた、ここの文書が適切に終了しないと文句を言います(最後の行に閉じEOF)
括弧があるためEOF
)。bash: warning: here-document at line 1 delimited by end-of-file (wanted `EOF')
bash
macOSのデフォルトバージョンなど、以前のバージョンを使用しない限り。
代わりに、これはコードを再解釈する必要がある文字列に変換するのを防ぎ、代わりに実行のためにシェルインタプリタに直接インラインシェルスクリプトとしてドキュメントを提供するので、より良いタスク選択になります。
bash <<'END_SCRIPT'
for i in *; do
printf 'Filename: "%s"\n' "$i"
done
END_SCRIPT
最初の例は単純なコマンドなので動作します。