使用find和sed在文件开头添加文件名

9

使用以下代码,将文件名添加到每行开头并将输出发送到单个文件中。

ls | while read file; do sed -e "s/^/$file/g" $file > out; done

我希望使用findexec或者xargs命令来执行与sed相同的替换操作 -

find . -type f -exec sed "s/^/{}/g" {} > out +

然而我遇到了一个错误 -

find: 只支持一个 {} 实例与 -exec ... + 结合使用

输入文件如下 -

fileA.txt

A1
A2

fileB.txt

B1
B2

期望的输出
fileA.txt A1
fileA.txt A2
fileB.txt B1
fileB.txt B2

我知道如何使用 awk 做到这一点,但我想用 sed、find 和 exec 或 xargs 来实现。
5个回答

6
 find . -type f |xargs awk '$0=FILENAME$0' > out

当我回答这个问题时,您的“不使用awk”指令还没有出现。无论如何,请看下面更新的答案:

根据评论更新

所以你想使用find、exec/xargs和sed来完成它。我的脚本需要 GNU Sed,希望您已经安装了它。

首先看一下单行命令:(好吧,> out 被省略了。您可以在行尾添加它。)

find . -type f | xargs -i echo {}|sed -r 's#(.\/)(.*)#cat &\|sed  "s:^:file \2 :g"#ge'

现在让我们来做个测试,看下面:

kent$  head *.txt
==> a.txt <==
A1
A2

==> b.txt <==
B1
B2

kent$  find . -type f | xargs -i echo {}|sed -r 's#(.\/)(.*)#cat &\|sed  "s:^:file \2 :g"#ge'
file b.txt B1
file b.txt B2
file a.txt A1
file a.txt A2

您的期望结果是什么?

简要说明

  • find ....|xargs -i echo {} 无需解释,只需按行打印文件名(带有前导"./"
  • 然后将文件名传递给sed命令,例如sed -r 's#(.\/)(.*)# MAGIC #ge'
  • 请记住,在上述命令中,我们有两个组\1:"./"\2 "a.txt"(文件名)
  • 由于在sed命令的末尾有e,所以MAGIC部分将被执行为shell命令。(需要GNU sed)
  • MAGICcat &\|sed "s:^:file \2 :g cat &仅输出文件内容,并管道到另一个sed。进行替换(s:..:..:g
  • 最后,MAGIC的执行结果将成为外部sed的替换。

关键在于GNU sed的'e'选项。


正如我在问题中所说的,我知道如何使用awk来完成这个任务,但我想用sed和find来完成它。 - Bryan
如果您有时间和兴趣,能否添加一些解释性的注释? - Bryan
说明已添加在答案中。 - Kent
@Bryan:我很好奇:这个解决方案在你的数据上表现如何? - A.H.
非常慢。我正在使用我的awk解决方案。 - Bryan

6

未经测试,请尝试使用xargs

find . -type f | xargs -I FILE sed "s/^/FILE/g" FILE > out

2
将“/”更改为“|”对我有用。
find . -type f | xargs -I FILE sed "s|^|FILE|g" FILE > out
- rickfoosusa

1
为什么不直接将第一行中的ls替换为find,像这样?
find . -type f | while read file; do sed -e "s|^|$file|" $file > out; done

你必须将分隔符从/更改为文件名中不包含的其他字符,我选择了|作为示例。


从我所看到的,使用-exec查找要快得多,而且我有成千上万个文件。 - Bryan
1
@Bryan:到目前为止还没有提到性能。由于find -execwhile循环都会为每个文件创建一个新的sed进程,因此你既不会获得也不会失去什么。此外:我预计大部分时间将花费在读写文件的内容上。 - A.H.
对于少量的文件,使用time find . -type f -exec sed "s/^/replacement/g" {} + 的实际时间为0m0.736秒,而使用time find . -type f | while read file; do sed -e "s|^|replacement|" $file ; done 的实际时间为0m3.165秒。使用xargs 替代 exec 稍微快一点。 - Bryan
@Bryan:对于一个“常量”replacement,你是正确的。但这不是问题所要求的。问题需要进行“变量”替换——每个文件都有不同的变量。因此,每个文件需要一个sed调用。因此,您不能使用find|xargsfind -exec + - A.H.

1
这个对我来说很好用,比Kent的答案更简单易用
注意:对于这个,完整路径名被插入了
find . -type f | xargs -r -t -i sed -r 's|^|'{}' |g' {}

请使用这个替代方案,只保留文件名的基本部分。
find . -type f | xargs -r -t -i sed -r -e 's|^|'{}' |g' -e 's|^.+/||g' {}

如果您对标准输出结果感到满意,那么可以在sed命令中添加-i开关以覆盖文件。

find . -type f | xargs -r -t -i sed -i -r -e 's|^|'{}' |g' -e 's|^.+/||g' {}

0

这样怎么样:

find . -type f | xargs -i echo FILE/{} > out

你能否修改你的问题,展示一个你想要的输出的例子吗?目前的描述让我有些困惑。 - Stephen Gross

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接