Bashヒアドキュメント内で変数を使用する


192

私はbashのヒアドキュメント内の変数を補間しようとしています:

var=$1
sudo tee "/path/to/outfile" > /dev/null << "EOF"
Some text that contains my $var
EOF

これは私が期待するようには機能しません($var文字どおりに扱われ、展開されません)。

sudo teeファイルの作成にはsudo が必要なので、使用する必要があります。次のようなことをする:

sudo cat > /path/to/outfile <<EOT
my text...
EOT

>outfilesudoを使用していない現在のシェルでファイルを開くため、機能しません。


9
これは理解できる混乱です!(それにあったかのようにヒアドキュメントの拡大オフ区切りターンの一部を引用し、以下に記載のように'')、しかしではない(それが中であるかのように区切りターン拡張を引用"")。ただし、 Perlでは直感は正しく、一重引用符で囲まれたヘレドキュメントは一重引用符で囲まれたかのように動作し、二重引用符で囲まれた識別子は二重引用符で囲まれたかのように動作し、逆引用符の付いた識別子はバッククォートのように動作します!参照:perlop:<< EOF
Nils von Barth

回答:


252

最初の質問への回答では、区切り文字を引用符で囲んでいるため、パラメーターの置換はありません-bashマニュアルには次のように記載されています

ヒアドキュメントの形式は次のとおりです。

      <<[-]word
              here-document
      delimiter

wordに対して、パラメーター展開、コマンド置換、算術展開、またはパス名展開は実行されません。wordのいずれかの文字が引用符で囲まれている場合、 区切り文字はwordの引用符の削除の結果であり、ヒアドキュメントの行は展開されません。単語が引用符で囲まれていない場合、ヒアドキュメントのすべての行は、パラメータ展開、コマンド置換、および算術展開の対象になります。[...]

<<EOF代わりに使用するように最初の例を変更する<< "EOF"と、それが機能することがわかります。

2番目の例では、シェルはsudoパラメーターを指定してのみ呼び出しcat、リダイレクトはsudo cat元のユーザーとしてのの出力に適用されます。あなたがしようとするとそれはうまくいきます:

sudo sh -c "cat > /path/to/outfile" <<EOT
my text...
EOT

興味がある場合は、次のようにすることもできます (cat > /path/to/outfile) <<EOFsudo sh -c ... <<EOF
。–

バッシュに埋葬されているのは、その理由です。
Landon Kuhn

96

で引用符を使用しないでください<<EOF

var=$1
sudo tee "/path/to/outfile" > /dev/null <<EOF
Some text that contains my $var
EOF

変数展開は、ヒアドキュメント内のデフォルトの動作です。この動作を無効にするには、ラベルを引用符で囲みます(一重引用符または二重引用符で)。


36

ここでの以前の回答に対する後期の結果として、おそらくすべてではなく一部の変数を補間する必要がある状況に陥ります。バックスラッシュを使用してドル記号とバックティックをエスケープすることで、これを解決できます。または、静的テキストを変数に入れることができます。

Name='Rich Ba$tard'
dough='$$$dollars$$$'
cat <<____HERE
$Name, you can win a lot of $dough this week!
Notice that \`backticks' need escaping if you want
literal text, not `pwd`, just like in variables like
\$HOME (current value: $HOME)
____HERE

デモ:https : //ideone.com/rMF2XA

-引用メカニズムのいずれかのことに注意してください\____HEREまたは"____HERE"または'____HERE'-すべての変数の展開を無効にし、リテラルテキストの一部にヒアドキュメントをオンにします。

一般的なタスクは、ローカル変数とスクリプトを組み合わせることです。スクリプトは、別のシェル、プログラミング言語、またはリモートホストで評価する必要があります。

local=$(uname)
ssh -t remote <<:
    echo "$local is the value from the host which ran the ssh command"
    # Prevent here doc from expanding locally; remote won't see backslash
    remote=\$(uname)
    # Same here
    echo "\$remote is the value from the host we ssh:ed to"
:

3
なぜこれが反対票が投じられたのかはわかりませんが、投票数が増えた回答には含まれていない有効なメモが追加されています。
1
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.