変数の値をコマンドの標準入力に渡す方法は?


105

私は、ある程度安全でなければならない、つまりコマンドのパラメーターを通じて安全なデータを渡さず、できれば一時ファイルを使用しないシェルスクリプトを書いています。コマンドの標準入力に変数を渡すにはどうすればよいですか?または、それが不可能な場合、そのようなタスクに一時ファイルを正しく使用するにはどうすればよいですか?


攻撃者は変更できます$PATHか?したがって、次のcatように置き換えることができます/bin/cat "$@" | tee /attacker/can/read/this/file
12431234123412341234123

回答:


74

次のように単純なもの:

echo "$blah" | my_cmd

7
変数のスペースに注意してくださいecho "$blah"
ジョナサンレフラー、2011年

13
あなたはどのように処理するかを見てみましょうblah=-nblah=-e...使用printf代わりに。unix.stackexchange.com/questions/65803/...
カミロ・マーティン

1
これは壊れやすく、エラーが発生しやすいようです。
ThorSummoner 2017年

19
6年後、この回答を削除できるとしたら、それを削除できます(しかし、それが受け入れられたため、できません...)
Oliver Charlesworth

1
@OliverCharlesworth、編集して使用しprintf '%s\n' "$blah"ませんか?1つの変更(に多くの落とし穴を避けることとechoステファンの優れた答えはで詳細にに入るの仕様、なぜですprintfより良いよりもechoのUnixとLinux、またはそのアプリケーション使用法セクションecho仕様それは完全だより簡潔にタッチ)合理的な答え。
Charles Duffy

192

値を渡すstdinはbashすることなど簡単なようです:

your-command <<< "$your_variable"

常に変数式を引用符で囲むようにしてください!

これはおそらくでのみ機能しbash、では機能しないことに注意してくださいsh


39
ヘレストリングス<<<が利用可能であるとは限りません。私が知る限り、それらはPOSIXベースではありません。で実行している限り、期待どおりに動作しますbash。彼らのOPは特に「bash」ではなく「shell」と言ったので、私はそれについてのみ述べます。彼は質問にタグを付けましたがbash...それでも、これは明らかに容認できる答えです。
JMベッカー

これは事実かもしれませんechoが、パイプの作成のためにメソッドを使用すると、機密情報がより簡単に漏洩する可能性があります。herestringコマンドは完全にによって処理されますがbash、(このように)この状況では、bashで機能することを理解している必要があります。そうでない場合、herestringをサポートしない結果として生成されるエラーメッセージも、上記の情報をリークします。
Steven Lu

@StevenLu Wait echoは組み込みです。パイプはありませんよね?それはUnixですが、それほど多くのUnixになることはできません。
カミロマーティン

4
@StevenLuはとprintf '%s\n' "$var"同じ結果を生成しますecho "$var"が、たとえば、var=-enbashを必要としない場合でもブレークしません。
カミロマーティン

1
また、ヒア文字列の文字列には改行が追加されます。
pdr

19

' echo "$var" | command操作は、標準入力がエコーされた行に制限されることを意味することに注意してください。端末も接続したい場合は、より洗練されている必要があります。

{ echo "$var"; cat - ; } | command

( echo "$var"; cat -   ) | command

これは、最初の行が内容であることを意味します$varが、残りはcatその標準入力を読み取ることから来ます。コマンドがあまり凝った動作を行わない場合(コマンドライン編集をオンにするか、または同様に実行する場合vim)は問題ありません。そうでなければ、あなたは本当に空想を得る必要があります-私は、expectまたはその派生物の1つが適切であると思います。

コマンドラインの表記は実質的に同じですが、2番目のセミコロンは括弧では必要ですが、括弧では必要ありません。


( echo "$LIST"; cat - ) | sed 1qこれは私にとってはうまくいきますが、このスクリプトを実行するときにctrl dを押す必要がありますか?
ガートカイケンズ

はい; これcat -は、EOFまたは割り込みが発生するまでキーボードから読み続けるため、control-Dを入力してEOFを通知する必要があります。
ジョナサンレフラー、

EOFを回避する方法はありますか?sedは猫を必要とする
Gert Cuykens

cat最初の行のように、端末入力が必要ない場合は、まったく使用する必要はありません。またはcat、ファイルの一覧表示に使用できます。または...コマンドで端末入力を読み取る場合は、入力の最後に達したことを通知する必要があります。またはあなたが使うことができます( echo "$var"; sed /quit/q - ) | command; これは、「quit」を含む行を入力するまで続きます。あなたはそれをどのように扱うかに無限に進歩的であることができます。ユーザーがエクアドルを使い始めたときに機能しなくなったプログラムの古い都市伝説に注意してください。彼らは首都キトの名前を入力し、プログラムは終了しました。
ジョナサンレフラー、

もし君がそういうならいいよ。しかし、なぜecho "$LIST" | sed 1q | ...ですか?それはあなたが何をしているのかによります。<<EOF表記は、ファイルダウン独自のどこかの行の先頭にEOFを要求すべきです。私はそれを使用しないと思います—しかし、あなたが何を達成しようとしているのかまだわかりません。単純な、echo "$LIST" | commandまたはecho $LIST | commandおそらく実際には十分でしょう(そして、2つの間の違いの重要性を知っていることが重要です)。
ジョナサンレフラー、

16

マーティンの答えが好きでしたが、変数の内容によっては問題が発生しました。この

your-command <<< """$your_variable"""

変数に "または!


4
しかし、なぜ?また、問題を再現できませfoo1=-; foo2='"'; foo3=\!; cat<<<"$foo1"; cat<<<"$foo2"; cat<<<"$foo3"ん。問題なく動作します。3つ"は正確には何をしますか?申し訳ありませんが、空の文字列を追加して追加しています。
16年

実際のことを試してください。コマンドのようにssh somehostです。変数はシェルスクリプトです。
ロバートジェイコブス

16
(cat <<END
$passwd
END
) | command

これcatは実際には必要ありませんが、コードをより適切に構造化するのに役立ち、コマンドへの入力として括弧内により多くのコマンドを使用することができます。


ただし、この方法では、コマンドに複数の行を渡すことができます。また、$passwd
含める

4
これは、可変コンテンツをパイプまたはプロセスのスヌーピングにリークしない、これまでのところ最良の答えです。
user2688272 2017年

8

マーティンの回答によると、ヒア文字列と呼ばれるbash機能があります(これ自体が、より広くサポートされているヒアドキュメント機能のバリアントです)。

http://www.gnu.org/software/bash/manual/bashref.html#Here-Strings

3.6.7ヒア文字列

ヒアドキュメントの変形であり、フォーマットは次のとおりです。

<<< word

単語が展開され、標準入力でコマンドに提供されます。

ヒア文字列はbashのみのように見えるので、移植性を向上させるために、PoltOSの回答にあるように、オリジナルのヒアドキュメント機能を使用することをお勧めします。

( cat <<EOF
$variable
EOF
) | cmd

または、上記のより簡単なバリアント:

(cmd <<EOF
$variable
EOF
)

これを他のコマンドにさらにリダイレクトしたくない場合は(、およびを省略でき)ます。


5

この堅牢で移植可能な方法は、すでにコメントに記載されています。スタンドアロンの答えである必要があります。

printf '%s' "$var" | my_cmd

または

printf '%s\n' "$var" | my_cmd

ノート:

  • それよりも優れechoています。理由はここにあります。なぜprintfより優れているのechoですか?
  • printf "$var"間違っている。最初の引数は、様々な配列が好きなフォーマットである%sか、\nされて解釈します。変数を正しく渡すには、それをフォーマットとして解釈してはなりません。
  • 通常、変数には末尾の改行は含まれません。前者のコマンド(を使用%s)は、変数をそのまま渡します。ただし、テキストを処理するツールは、不完全な行を無視したり、文句を言う場合があります(テキストファイルが改行で終わる必要がある理由を参照してください)。したがって%s\n、変数の内容に改行文字を追加する後者のコマンド(を使用)が必要になる場合があります。非自明の事実:

    • ここでBash(<<<"$var" my_cmd)内の文字列は改行を追加します。
    • 改行を追加するメソッドmy_cmdは、変数が空または未定義であっても、空でないstdinになります。

4

これを試して:

echo "$variable" | command

しかし、$ variableの内容はps -u、エコーが実行されているときの出力などに表示されませんか?

2
いいえ、そうではありません。echoは組み込みなので、psに表示するプロセスはありません
unbeli

2
変数のスペースに注意してくださいecho "$variable"
ジョナサンレフラー、2011年

そうです、bashはダブルスペースを食べますが、よりスマートなシェルは食べません
unbeli

-1

ただやる:

printf "$my_var" | my_cmd

varにスペースが含まれていない場合は、引用符を省略できます。
bashを使用している場合は、次のようにすることもできます。

echo -n "$my_var" | my_cmd

末尾に改行を追加して変数をパイプするため、-nなしでエコーを使用しないでください。


1
$ my_varがの場合、機能しません。printfは%s何も出力しません。my_var="%s"; printf "$my_var"; -たぶんprintf "%s" "$my_var" | my_cmd やってみますか?
hanshenrik 2018
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.