Bashのコマンドの前に環境変数を設定すると、パイプの2番目のコマンドでは機能しません


351

特定のシェルでは、通常、変数を設定してからコマンドを実行します。最近、変数定義をコマンドの前に付けるという概念について学びました。

FOO=bar somecommand someargs

これはうまくいきます... LC_ *変数(コマンドに影響を与えるように見えるがその引数(たとえば、 '[az]'の文字の範囲には影響しない)を変更するとき、または出力を別のコマンドにパイプするときは、次のように機能しません

FOO=bar somecommand someargs | somecommand2  # somecommand2 is unaware of FOO

somecommand2の前に "FOO = bar"を追加することもできますが、これは機能しますが、不要な重複が追加され、変数に応じて解釈される引数( '[az]'など)には役立ちません。

では、これを1行で行うにはどうすればよいでしょうか。

私は次の順序で何かを考えています:

FOO=bar (somecommand someargs | somecommand2)  # Doesn't actually work

良い答えがたくさんありました!目標は、これを1行に保つことです。できれば「エクスポート」を使用しないでください。Bashへの呼び出しを使用する方法は全体的に最高でしたが、「export」が含まれている括弧付きのバージョンは少しコンパクトでした。パイプではなくリダイレ​​クトを使用する方法も興味深いです。


1
(T=$(date) echo $T)動作します
vp_arth 2015年

クロスプラットフォーム(Windowsを含む)スクリプトまたはnpmベースのプロジェクト(jsなど)のコンテキストでは、クロス環境モジュールを確認することをお勧めします
フランクノッケ2017

5
私は答えの1 つがなぜこれだけの種類の作業、つまり、呼び出しの前に変数をエクスポートすることと同等ではないのかを説明することを望んでいました。
Brecht Machiels 2017年

4
なぜここで説明されていますstackoverflow.com/questions/13998075/...
ブレヒトMachiels

回答:


317
FOO=bar bash -c 'somecommand someargs | somecommand2'

2
これは私の基準を満たします(「エクスポート」を必要としないワンライナー)... 「bash -c」呼び出さずにこれを行う方法はありません(たとえば、括弧の創造的な使用)。
MartyMacGyver

1
@MartyMacGyver:考えられるものはありません。中括弧でも機能しません。
追って通知があるまで一時停止。

7
somecommandsudoとして実行する必要がある場合は-E、変数を渡すためにフラグをsudoに渡す必要があることに注意してください。変数は脆弱性をもたらす可能性があるためです。stackoverflow.com/a/8633575/1695680
ThorSummoner 2015年

11
コマンドにすでに2つのレベルの引用符がある場合、この方法は引用符の地獄のために非常に不満足なものになることに注意してください。そのような状況では、サブシェルでのエクスポートがはるかに優れています。
Pushpendre 2016年

奇数:OSXでFOO_X=foox bash -c 'echo $FOO_X'期待どおりに動作しますが、特定の変数名では失敗します:DYLD_X=foox bash -c 'echo $DYLD_X'空白をエコーし​​ます。どちらもeval代わりに使用していますbash -c
mwag

209

変数をエクスポートするのはどうですか?サブシェルの内部だけですか?:

(export FOO=bar && somecommand someargs | somecommand2)

キースには、コマンドを無条件に実行するために、これを行うというポイントがあります。

(export FOO=bar; somecommand someargs | somecommand2)

15
;代わりに使用し&&ます。方法はありませんexport FOO=barが失敗しようとしているが。
キース・トンプソン、

1
@MartyMacGyver:&&左のコマンドを実行し、左のコマンドが成功した場合にのみ右のコマンドを実行します。;両方のコマンドを無条件に実行します。Windowsのbatch(cmd.exe)と同等のものは;です&
キース・トンプソン、

2
zshでは、このバージョンのエクスポートを必要としないようです:(FOO=XXX ; echo FOO=$FOO) ; echo FOO=$FOOyields FOO=XXX\nFOO=\n
ランピオン2013

3
@PopePoopinpants:その場合はsource(別名.)を使用しないのはなぜですか?また、最近で$(command)はバックティックを使用しないでください。これが理由の1つです。使用する方が安全です。
0xC0000022L 2014年

3
とてもシンプルでありながらとてもエレガントです。そして、私は現在の答えと同じサブシェルを開始するので、受け入れられた答えよりもあなたの答えが好きです(そうではないかもしれませんがbash、何か他のものである可能性がdashあります)。コマンドargs(someargs)内。
メッキー2014年

45

あなたも使うことができますeval

FOO=bar eval 'somecommand someargs | somecommand2'

この答えevalは誰にとっても喜ばしいとは思われないので、はっきりさせておきます。書いたとおりに使用すると、一重引用符があれば、完全に安全です。外部プロセス(承認された回答など)を起動せず、追加のサブシェル(他の回答など)でコマンドを実行しないため、これは良いことです。

通常のビューがいくつかあるので、これに代わる方法を提供することはおそらくeval誰にとっても喜ばしいことであり、この迅速なeval「トリック」のすべての利点(そしておそらくそれ以上)を持っています。関数を使うだけ!すべてのコマンドで関数を定義します。

mypipe() {
    somecommand someargs | somecommand2
}

次のような環境変数で実行します。

FOO=bar mypipe

7
@Alfe:承認された回答も反対投票しましたか?と同じ「問題」を示すからevalです。
gniourf_gniourf 2016年

10
@Alfe:残念ながら私はあなたの批判に同意しません。このコマンドは完全に安全です。あなたは、いったい何がeval悪いのか理解していないのに、一度読んだ人が悪い人のように聞こえevalます。そして、おそらくあなたは結局この答えを本当に理解していないでしょう(そして実際にはそれで何も問題はありません)。同じレベルで:lsが悪いので for file in $(ls)悪いと思いますか?(そして、ええ、あなたは受け入れられた回答に反対票を投じなかったし、コメントも残しませんでした)。SOは時々そのような奇妙でばかげた場所です。
gniourf_gniourf

7
@Alfe:私があなたがかつて読んだ人evalが何が悪かを理解していないのは悪だと本当に聞こえるevalとき私はあなたの文を参照しています:この答えは、話するときに必要なすべての警告と説明が欠けていますeval eval悪くも危険でもありません。せいぜいbash -c
gniourf_gniourf

1
投票は別として、@ Alfeが提供するコメントは、受け入れられた回答が何らかの方法でより安全であることを何らかの形で示唆しています。の使用に関して安全ではないと思われることを説明することで、もっと役立つはずですeval。提供された回答では、引数は変数展開から保護するために単一引用符で囲まれているため、回答に問題はありません。
ブレット・ライアン

懸念を1つの新しいコメントに集中させるためにコメントを削除しました。これ evalは一般的なセキュリティの問題です(bash -cそれほど明確ではありませんが)。不注意なユーザーが答え(FOO=bar eval …)を取り、それを自分の状況に適用すると、問題が発生します。しかし、私が何かを改善するよりも、私が彼および/または他の回答に反対票を投じるかどうかを把握することは、回答者にとって明らかに重要でした。前に書いたように、公平性が主な関心事であってはなりません。他のどの回答よりも悪くないことも無視されません
Alfe

12

を使用しenvます。

たとえば、env FOO=BAR commandcommand実行が終了すると、環境変数は再び復元/変更されないことに注意してください。

シェルの置換について注意してください。つまり$FOO、同じコマンドラインで明示的に参照したい場合は、シェルインタープリターが実行に置換を実行しないように、エスケープする必要がある場合がありますenv

$ export FOO=BAR
$ env FOO=FUBAR bash -c 'echo $FOO'
FUBAR
$ echo $FOO
BAR

-5

シェルスクリプトを使用します。

#!/bin/bash
# myscript
FOO=bar
somecommand someargs | somecommand2

> ./myscript

13
あなたはまだ必要exportです。それ以外の場合$FOOは、環境変数ではなくシェル変数になるため、somecommandまたはからは見えませんsomecommand2
キース・トンプソン、

それは機能しますが、1行のコマンドを使用する目的に反します(私は、比較的単純なケースでマルチライナーやスクリプトを回避するためのより創造的な方法を学習しようとしています)。@Keithが言ったことは、少なくともエクスポートのスコープはスクリプトのままです。
MartyMacGyver
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.