シェル変数を使用したコマンドの実行

シェル変数を使用したコマンドの実行

変数にunixコマンドがあります。

cmd="find /path/to/webpage -type f | grep -v .svn | xargs grep $@"
`$cmd`
find: paths must precede expression
Usage: find [-H] [-L] [-P] [path...] [expression]

$cmdBashスクリプトでコマンドを実行しようとすると機能しません。ただし、同じコマンドをコピーして貼り付けると機能します。何が間違っているのか教えてもらえますか?

パスの周りに引用符を入れようとしましたが、同じエラーが発生しました。

cmd="find \"/path/to/webpage\" -type f | grep -v .svn | xargs grep $@"
find: paths must precede expression
Usage: find [-H] [-L] [-P] [path...] [expression]

パラメータを削除すると、-type f次のエラーが発生します。

cmd="find /path/to/webpage | grep -v .svn | xargs grep $@"
find: invalid predicate `-v'

これによりパイプが認識されないようです。動作させるにはどうすればよいですか?

答え1

他の人はそれを行う方法を説明しました。ここで何が起こっているのか説明します。|変数が拡張されると、パイプ文字はパイプを形成せず、リテラル文字として機能します。したがって、find次のパラメーターを使用して実行します。

{"/path/to/webpage", "-type", "f", "|", "grep", "-v", ".svn", "|", ...}

をパスとして解釈|し、式(-type f)の前に現れるべきだと文句を言います。

`$cmd`もう一つの大きな間違いは、それを唯一のコマンドラインとして使用することです。$cmd(つまりfind ...)成功し、同様の出力を生成すると、rm -rf /ユーザーの代わりに実行されます。データをコードとして扱うときは注意してください!

改善 1. find ... | grep -v ...出力から何かを除外する悪い方法です。find名前付きサブディレクトリ全体を移動し、.svn行が作成されますが、後で削除されます。ただ私にfind言わなければならないのか?

find path -type f | grep -v .svn                # don't do this
find path -name .svn -prune -o -type f -print   # do this instead

改善 2.findandを組み合わせるときは、xargs常に-print0infind-0inを使用してくださいxargs

find path ... -print0 | xargs -0 -r grep ...    # I'd also recommend -r

または正確にこれを行うこともできますgrep

grep --recursive --exclude-dir=.svn pattern path

答え2

実際に変数からコードを実行するには、を使用できますeval

cmd="find /path/to/webpage -type f | grep -v .svn | xargs grep something"
eval "$cmd"

しかし、withに引数を渡そうとするので、$@必要なのは関数です。

webgrep() {
    find /path/to/webpage -type f | grep -v .svn | xargs grep "$@"
}

スペース文字を含むすべてのパスに問題が発生することに注意してください。またはマイナス記号で始まるパターン。.svnディレクトリを無視する前に、ディレクトリの内容全体を確認する必要があります。ユーザーが誤って複数のパラメータを渡した場合(スキーマが正しく引用されていない場合など)、処理することをお勧めします。より良い方法は

webgrep() {
    find /path/to/webpage -name .svn -prune -o -type f -exec grep -e "$*" {} +
}

それからこう呼んでください。

webgrep PATTERN

答え3

次のように変数を作成します。

cmd=$(find /path/to/webpage -type f | grep -v .svn | xargs grep $@)

または

cmd=`find /path/to/webpage -type f | grep -v .svn | xargs grep $@`

または、エイリアスがより適している可能性があります。

alias cmd="find /path/to/webpage -type f | grep -v .svn | xargs grep $@"

答え4

いいえ経験上、コードを変数に入れます。機能を使用してください。

cmd() { 
  find /path/to/webpage -type f |
    grep -v .svn                | 
    xargs grep $@
}

cmd "$@"

結局入れなければならないならシンプルコードは変数にあります(そうではありませんが、そうする場合は...)。上記のようにパイプのようなものを挿入したりeval…なしでリダイレクトすることはできません。それもしないでください、ハハ

ただし、サブシェルでコマンドを実行し、それを出力に置き換えるバックティック内で実行しないでください。これにより、出力はパーサーが実行コマンドで受け取ることになります。

$: `echo foo`
bash: foo: command not found

関連情報