如何在 bash 中通过扩展功能显示最后一个命令

如何在 bash 中通过扩展功能显示最后一个命令

我正在使用这样的功能。

$ 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

解释

这个特定版本的函数会以不同的方式执行以下操作。

  1. 我们用您的命令定义一个变量$cmd=(find....)。该命令被包装到一个数组中,(..)
  2. $cmd我们使用回显构造的数组printf。我们使用*符号传递数组的元素${cmd[*]},以便将数组作为单个字符串而不是离散的元素列表来获取。
  3. 最后我们评估 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 ...

相关内容