変数に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]
$cmd
Bashスクリプトでコマンドを実行しようとすると機能しません。ただし、同じコマンドをコピーして貼り付けると機能します。何が間違っているのか教えてもらえますか?
パスの周りに引用符を入れようとしましたが、同じエラーが発生しました。
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.find
andを組み合わせるときは、xargs
常に-print0
infind
と-0
inを使用してください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