gpt4 book ai didi

bash - 对 grep 列出的*每个*项目执行操作

转载 作者:行者123 更新时间:2023-11-29 08:53:58 28 4
gpt4 key购买 nike

如何对 grep 列出的每个项目分别执行操作?

背景:

我使用 grep 列出所有包含特定模式的文件:

grep -l '<pattern>' directory/*.extension1

我想删除所有列出的文件还有所有具有相同文件名但不同扩展名的文件:.extension2

我尝试使用管道,但它似乎将 grep 的输出作为一个整体。

在 find 中有 -exec 选项,但 grep 没有类似的选项。

最佳答案

如果我理解你的规范,你想要:

grep --null -l '<pattern>' directory/*.extension1 | \
xargs -n 1 -0 -I{} bash -c 'rm "$1" "${1%.*}.extension2"' -- {}

这与@triplee 的评论所描述的基本相同,只是它是换行安全的。

这是怎么回事?

grep--null 将返回以空值而不是换行符分隔的输出。由于文件名中可以​​包含换行符,因此无法安全地解析 grep 的输出,但 null 不是文件名中的有效字符,因此是一个很好的分隔符。

xargs 将采用换行符分隔的项目流并执行给定命令,将尽可能多的这些项目(每个参数一个)传递给给定命令(或 echo 如果没有给出命令)。因此,如果你说:

printf 'one\ntwo three \nfour\n' | xargs echo

xargs 会执行 echo one 'two three' four。这对文件名不安全,因为文件名可能包含嵌入的换行符。

-0 切换到 xargs 将其从查找换行符更改为空分隔符。这使得它与我们从 grep --null 获得的输出相匹配,并且可以安全地处理文件名列表。

通常 xargs 只是将输入附加到命令的末尾。 -I 切换到 xargs 将其更改为用输入替换指定的替换字符串。要了解这个想法,请尝试这个实验:

printf 'one\ntwo three \nfour\n' | xargs -I{} echo foo {} bar

并注意与早期 printf | 的区别xargs 命令。

在我的解决方案中,我执行的命令是 bash,我将 -c 传递给它。 -c 开关使 bash 执行以下参数中的命令(然后终止)而不是启动交互式 shell。下一个 block 'rm "$1""${1%.*}.extension2"'-c 的第一个参数,是将由庆典-c 的脚本参数之后的任何参数都被指定为脚本的参数。这,如果我要说:

bash -c 'echo $0' "Hello, world"

然后 Hello, world 将被分配给 $0(脚本的第一个参数)并且在脚本中我可以 echo 它返回.

由于 $0 通常是为脚本名称保留的,所以我传递了一个虚拟值(在本例中为 --)作为第一个参数,然后代替我编写的第二个参数 {},这是我为 xargs 指定的替换字符串。这将由 xargs 替换,每个文件名在执行 bash 之前从 grep 的输出中解析。

迷你 shell 脚本可能看起来很复杂,但其实很简单。首先,整个脚本用单引号引起来以防止调用 shell 解释它。在脚本中,我调用 rm 并向其传递两个要删除的文件名:$1 参数,这是在上面替换替换字符串时传递的文件名,以及 ${1%.*}.extension2。后者是 $1 变量的参数替换。重要的部分是 %.* 表示

  • % "从变量末尾开始匹配,去掉匹配模式的最短字符串。
  • .* 模式是一个句点后跟任何内容。

这有效地从文件名中删除了扩展名(如果有的话)。大家可以自己观察效果:

foo='my file.txt'
bar='this.is.a.file.txt'
baz='no extension'
printf '%s\n'"${foo%.*}" "${bar%.*}" "${baz%.*}"

由于扩展名已被剥离,我将所需的备用扩展名 .extension2 连接到剥离的文件名以获得备用文件名。

关于bash - 对 grep 列出的*每个*项目执行操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9682721/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com