変数に保存されているコマンドを実行する


11

変数にコマンドを保存しています。変数$iに値があるとします。

cat -nT index.php |grep 'someregex'

上記の変数を入力$iして実行しようとすると、シェルが変数全体を1つのコマンドとして実行しようとするため、失敗します。私もバッククォートを使っeval($i)て入れてみ$iました。

$iコマンドのようにシェルを実行するにはどうすればよいですか?そしてなぜそれは同じように機能しないのですか?

$i='echo hi'; $i

それは私が一重引用符で一種のハックしなければならなかったからですか?(ネストできないため)現在のところ、私の解決策は

echo $i > /foo;  . /foo

ただし、このためだけにファイルを作成するのではなく、後で削除するだけです。

「一重引用符でハッキングしたのは、私がしたことです。

$i='cat index.php | grep -P '"'"'MYREGEXHERE'"'"

4
問題は、なぜコマンドが最初から変数に格納されているのかということです。コマンドを実行するときにコマンドをアセンブルし、オプションの引数を変数または配列に格納したほうがよいでしょう。持っているスクリプト全体を見せられますか?
slhck 2013年

回答:


18

短い答え:BashAQ#50を参照してください:コマンドを変数に入れようとしていますが、複雑なケースは常に失敗します!

長い答え:bashがコマンドラインを解析する順序が原因です。具体的には、変数値を展開する前にパイプやリダイレクトなどを探し、戻ってパイプなどを展開値で再検索しません。基本的に、変数は解析プロセスのほぼ半分で置換されるため、値は実行前に解析されるだけです。

これを解決するには、@ slhckの質問に答える必要があります。なぜコマンドが最初から変数に格納されているのですか?あなたが解決しようとしている実際の問題は何ですか?実際の目標に応じて、いくつかの可能な解決策があります。

  • 変数に格納せず、直接実行してください。後で使用するためにコマンドを保存するのは難しいので、本当に必要ない場合は、しないでください。

  • 変数の代わりに関数を使用します。結局のところ、それが目的です。

    i() { cat -nT index.php |grep 'someregex'; }
    i

    これの主な欠点は、関数を動的に作成できないことです。つまり、関数にコードを条件付きで含めたり除外したりすることはできません(ただし、関数自体には、実行時に選択される条件付き要素を含めることができます)。

  • を使用しevalます。予期しない動作が発生しやすいため、これは最後の手段と考える必要があります。それは本質的にコマンドを別の完全な解析パスで実行するので、すべてのパイプなどが完全な意味を持ちますが、データだと思ったコマンドの一部も解析されて実行される可能性があることも意味します。シェルのメタ文字(パイプ、セミコロン、引用符/アポストロフィなど)を含むファイル名は、奇妙で、時には危険な影響を与える可能性があります。を使用する場合evalは、少なくとも文字列を二重引用符で囲みます。それ以外の場合、その内容は基本的に1.5回解析され、さらに奇妙な結果になります。

    i="cat -nT index.php |grep 'someregex'"
    eval "$i"

編集:別の標準のコマンドで変数を格納するアプローチは、単純な変数の代わりに配列を使用することです。これにより、複雑な引数(スペースを含むなど)を含むコマンドを問題なく保存できますが、パイプやリダイレクトなどは保存できません。そのため、この特定のケースでは、配列アプローチは役に立ちません。


evalメソッドの+1 。これは私が同じ質問をするのを止めました:)。sudo rsync -aAHXi -n --delete-excluded --exclude={"/dev/*","/proc/*","/sys/*","/tmp/*","/run/*","/lost+found","/mnt/DATA/*","/var/log/*","/var/swap","/var/cache/apt/archives/*.deb"} -e ssh root@piac_wireless:/ /home/mrx/Docs/RPi/backup/piac/piac_usb-rootそのようなものが、除外を正しく実行していませんでした。
デンテックス2018

@dentex私はevalこれを使用しないことを強くお勧めします- 失敗する方法が多すぎるためです。これを行うには、配列の方が適しています。例についてここここ、およびここを参照してください。
Gordon Davisson

提案をありがとう。除外リストをrsyncに渡すために、配列を使用してソリューションを実装しようとします。
dentex

4

これはうまくいくはずです:

a="cat -nT index.php |grep 'someregex'"
eval "$a"

eval潜在的な脆弱性や予期しない動作状況を引き起こすことに注意してください。使用する場合は、特に注意してください。


を使用する場合はevaleval "$i"余分な奇妙な影響を避けるために、二重引用符()を使用する必要があります。たとえば、これを試してa="cat -nT index.php |grep ' .* '"(つまり、正規表現は2つのスペースとその間の文字のシーケンスと一致する必要があります)、実際に何が起こるかを確認します。追加のクレジットについてはそれが発生する理由を説明てください。
Gordon Davisson 2013年

@GordonDavissonの二重引用符が追加されました。
jlliagre 2013年

2

変数を宣言するときは、ドル記号を接頭辞として使用しないでください。

これを試して:

i='echo hi'; $i

1
それは正しいですが、OPの質問に対する答えではありません。
slhck 2013年

その私のためにREALY:P
nwgat
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.