【问题标题】:add filename to beginning of file using find and sed使用 find 和 sed 将文件名添加到文件的开头
【发布时间】:2011-12-10 09:09:03
【问题描述】:

使用以下内容,我将文件名添加到每行的前面并将输出发送到单个文件。

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

我想执行相同的 sed 替换,但使用 findexecxargs 命令 -

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

但我得到一个错误 -

发现:-exec ... + 仅支持一个 {} 实例

输入文件是这样的-

文件A.txt

A1
A2

文件B.txt

B1
B2

想要的输出

fileA.txt A1
fileA.txt A2
fileB.txt B1
fileB.txt B2

我知道如何使用 awk 执行此操作,但我想使用 sed、find 和 exec 或 xargs 执行此操作。

【问题讨论】:

    标签: shell sed find


    【解决方案1】:

    未经测试,尝试使用 xargs

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

    【讨论】:

    • 将 '/' 更改为 '|'为我工作。 find . -type f | xargs -I FILE sed "s|^|FILE|g" FILE > out
    【解决方案2】:

    怎么样:

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

    【讨论】:

    • 您能否修改您的问题以显示您想要的输出类型的示例?目前写的不太明白。
    【解决方案3】:

    您为什么不像这样将第一行中的ls 替换为find

    find . -type f | while read file; do sed -e "s|^|$file|" $file > out; done
    

    您只能将 s 的分隔符从 / 交换为文件名中未包含的其他内容。我以| 为例。

    【讨论】:

    • 据我所见,使用 -exec 查找要快得多,而且我有数万个文件。
    • @Bryan:目前还没有提到性能。由于find -execwhile 循环都会为每个文件创建一个新的sed 进程,因此您既不会获得也不会失去某些东西。此外:我预计,大部分时间将花在读取和写入文件的内容上。
    • 仅供参考,用于少量文件 - 时间查找。 -type f -exec sed "s/^/replacement/g" {} + 需要真正的 0m0.736s 但时间 find 。 -类型 f |读取文件时;做 sed -e "s|^|替换|" $文件;完成需要真正的 0m3.165s。并且使用 xargs 而不是 exec 会快一点
    • @Bryan:对于 常量 replacement,你是对的。但这不是问题中所问的。问题需要 variable 替换 - 每个文件的变量。因此每个文件需要一个sed 调用。所以你既不能使用find|xargs也不能使用find -exec +
    【解决方案4】:
     find . -type f |xargs awk '$0=FILENAME$0' > out
    

    当我回答这个问题时,您的“no 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 -r 's#(.\/)(.*)# MAGIC #ge'这样的sed行
    • 请记住,在上面的行中,我们有两个组\1: "./"\2 "a.txt"(filename)
    • 因为我们在 sed 行的末尾有 e,所以 MAGIC 部分将是 作为 shell 命令执行。(需要 GNU sed)
    • MAGICcat &amp;\|sed "s:^:file \2 :g cat & 只是输出文件 内容,并通过管道传输到另一个 sed。替换 (s:..:..:g)
    • 最后,MAGIC 的执行结果是替换 外部 sed。

    关键是 Gnu sed 的 'e'。

    【讨论】:

    • 正如我在问题中所说,我知道如何使用 awk 来执行此操作,但我想使用 sed 和 find 来执行此操作。
    • 谢谢,如果您有时间和兴趣,可以添加一些解释性的 cmets 吗?
    • 答案中添加了解释。
    • @Bryan:我很好奇:这个解决方案对您的数据的性能如何?
    • 非常慢。我正在使用的是我的 awk 解决方案。
    【解决方案5】:

    这个对我来说很好用,而且比肯特的回答更简单
    注意:比为那个插入完整路径名

    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' {}
    

    【讨论】:

      猜你喜欢
      • 2015-05-06
      • 1970-01-01
      • 1970-01-01
      • 2021-11-14
      • 2016-08-27
      • 1970-01-01
      • 2014-08-29
      • 1970-01-01
      相关资源
      最近更新 更多