我正在使用这样的功能。
$ find-grep () { find . -type f -name "$1" -print0 | xargs -0 grep "$2" ; }
我输入后:
$ find-grep *.c foo
我想扩展最后一个命令字符串。在这种情况下:
find . -type f -name "*.c" -print0 | xargs -0 grep "foo"
有办法轻松做到吗?
答案1
@slm 的更理智的版本:
find-grep() {
cmd=(find . -type f -name "$1" -exec grep "$2" {})
printf '%q ' "${cmd[@]}"
printf '+\n'
"${cmd[@]}" +
}
(不需要管道或xargs
此处)或者:
find-grep () (
set -x
find . -type f -name "$1" -exec grep "$2" {} +
)
(请注意,()
而不是{}
启动一个子shell来限制 的范围set -x
。请注意,它不会导致更多进程被分叉,只是fork
将要执行的进程find
更早完成)。
请记住,您需要引用通配符,以便 shell 不会扩展它们:
find-grep '*.c' pattern
相反,如果您希望将其推送到历史记录,以便在按下该Up键时看到展开的命令,您可以这样写:
find-grep() {
cmd=$(printf '%q ' find . -type f -name "$1" -exec grep "$2" {})+
history -s "$cmd"
eval "$cmd"
}
答案2
以下是一种方法:
$ find-grep () {
cmd=(find . -type f -name \"$1\" -print0 \| xargs -0 grep \"$2\")
printf "%s\n" "${cmd[*]}"
eval "${cmd[*]}"
}
例子
这是一些示例数据。
$ ls -l
total 8
-rw-rw-r-- 1 saml saml 4 Sep 21 10:44 1.c
-rw-rw-r-- 1 saml saml 4 Sep 21 10:44 2.c
-rw-rw-r-- 1 saml saml 0 Sep 21 10:22 3.c
-rw-rw-r-- 1 saml saml 0 Sep 21 10:22 4.c
-rw-rw-r-- 1 saml saml 0 Sep 21 10:22 5.c
这是我们的函数的实际运行,其中 2 个文件包含字符串“foo”。
$ find-grep '*.c' "foo"
find . -type f -name "*.c" -print0 | xargs -0 grep "foo"
./2.c:foo
./1.c:foo
解释
这个特定版本的函数会以不同的方式执行以下操作。
- 我们用您的命令定义一个变量
$cmd=(find....)
。该命令被包装到一个数组中,(..)
。 $cmd
我们使用回显构造的数组printf
。我们使用*
符号传递数组的元素${cmd[*]}
,以便将数组作为单个字符串而不是离散的元素列表来获取。- 最后我们评估 array
$cmd
并运行它。
另一种方法
您还可以像这样包装该函数:set -x ...function... set +x
,其效果是仅在 的持续时间内打开调试...function...
,然后将其关闭。
$ find-grep () {
set -x
find . -type f -name "$1" -print0 | xargs -0 grep "$2"
set +x
}
例子
$ find-grep *.c foo
+ find . -type f -name '*.c' -print0
+ xargs -0 grep foo
+ set +x
这种方法不太容易阅读,但它向您展示了相同的总体功能,只是根据它们的执行方式进行了分解。首先是find ...
,然后是xargs ...
。