我在变量中有一个 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", "|", ...}
它将 the 解释|
为一条路径,并抱怨它应该出现在表达式 ( -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
......并且也不要这样做,哈哈
但不要在反引号中执行它,反引号会在子 shell 中运行命令并将其替换为输出,以便输出成为解析器作为要执行的命令接收的内容:
$: `echo foo`
bash: foo: command not found