【问题标题】:how to use the name of the input file in sed replace如何在 sed 替换中使用输入文件的名称
【发布时间】:2013-12-13 13:49:54
【问题描述】:

我有几个文件,我想用文件本身的名称替换某个单词..

例如,我有两个名为 test1.txt 和 test2.txt 的文件

两个文件是相等的,看起来像

bla1,bla2,温度 bla2,bla3,温度

使用 sed 我想用文件本身的名称替换单词 temp

所以在 sed 操作之后我有 2 个不同的文件

test1.txt ,看起来像:

bla1,bla2,test1 bla2,bla3,test1

test2.txt,看起来像:

bla1,bla2,test2 bla2,bla3,test2

所以我的问题...我如何使用输入文件本身的实际名称作为替换命令的一部分?

sed "s/temp/  ??filename??/   ???  "    *.txt

感谢您的建议

【问题讨论】:

    标签: sed filenames


    【解决方案1】:

    我不确定您是否可以使用sed 引用文件名,尽管我可能是错的。您可能会使用 shell hack。用文件名替换所有出现的temp 的更好方法是使用以下awk 脚本:

    $ awk '{gsub(/temp/,FILENAME)}1' file
    

    【讨论】:

    • 该死!我发布了我荒谬的长答案,却没有意识到 awk 中有一个变量。不错。
    • @user3099593 on stackoverflow 表明你对答案印象深刻的方式是支持它(当你获得足够的代表时)。您现在应该通过单击该答案旁边的勾号来接受对您最有用的答案。
    • 一些附加问题... 1)我想剥离文件名的文件类型 2)我想放“;”围绕文件名;文件名; 3)我想将输出写回我当前正在读取和更改的同一个文件。所以在我的用例中,我有一个 *.txt 文件过滤器,它应该处理几十个文件。只是将输出定向到带有> outfile 的文件将最终得到一个输出文件中所有文件的所有数据..那么实际上如何重用当前文件也作为输出文件的名称..或者是打开的文件,我需要一个临时文件吗... 非常感谢所有人!
    【解决方案2】:

    使用awk,awk有FILENAME变量:

    awk '{sub(/temp/,FILENAME)}7' yourfile
    

    【讨论】:

      【解决方案3】:
      awk 'BEGIN{FS=OFS=","} {$NF=FILENAME}1' file
      

      this 和 sub() 解决方案之间的区别在于,即使文件中的其他位置存在“temp”一词,它也可以工作,例如如果“bla1”包含“温度”这个词。

      如果您需要从发布的所需输出中显示的文件名中删除“.txt”,请将其调整为:

      awk 'BEGIN{FS=OFS=","} {t=FILENAME; sub(/\.txt$/,"",t); $NF=t}1' file
      

      您可能可以编辑 FILENAME 本身,但如果您不必这样做,我发现最好不要弄乱内置变量。

      【讨论】:

      • 我不确定这个例子是否具有代表性,如果是,这将是一个更好的解决方案。
      • 如果不是,那我们就是在黑暗中拍摄 :-)
      • 我们不总是……只是有时 OP 比其他人更聪明,并且正朝着正确的方向。
      【解决方案4】:

      如果可以的话,你可以用一点 bash 来帮助你。

      find . -name "test*.txt" -type f | awk -F '/' '{print $2;}' | while read file; do sed -i "s|temp|$file|" ./$file; done
      

      这是对脚本的一种修改,我必须做类似的事情。毫无疑问可以缩短。

      【讨论】:

      • 没有。不不不。最后 - 不。 :-) 上述不仅冗长且效率低下,而且还有几个隐蔽的错误,会让您因各种文件名而烦恼。
      • 你不喜欢吗? :)
      • 我现在正在重写我的命令以使用 awk 和 gsub,但我认为我无法绕过创建临时文件。哦,对于 FILENAME 和 sed -i 的组合。
      • 那将是 gawk -i inplace 'script' file 与 gawk 4.1.0 及更高版本。
      • 不错!我需要 debian 将其添加到 wheezy 存储库中,但至少我知道修复即将到来。
      【解决方案5】:

      文件名没有 sed 内部变量,因此您需要一些以前的批处理命令用于通用进程

      for FileName in MyFileShellFilter
       do
          cat <> ${FileName} | sed "s|,temp$|,${FileName}|"
       done
      

      只需谨慎使用文件名,它们通常没有\,但可能有&amp;,即s// 特殊含义。我使用| 作为分隔符以允许在文件名中使用/,但由于这个原因,文件名中不允许使用未转义的|(通常不允许)

      【讨论】:

      • 还要注意包含空格或 *s 或任何其他通配符的文件名,因为它们会导致不良结果,并注意 shell 可能会在打开文件进行读取之前决定覆盖您的文件,因此你最终可能会得到一个空文件。
      • 好话(+1),我必须在猫级别包围“$ {filename}”。 *sis 在进入循环之前通常由 shell 扩展。
      • 是的,最大的问题是 cat &lt;&gt; file | foo 可以被 shell 解释,这样 shell 做的第一件事就是 &gt; file 部分,所以它会立即删除你的输入文件,然后是 @ 987654330@ 之后在现在为空的文件上。
      • 我在另一个帖子上得到了同样的评论,经过测试,它似乎依赖于 shell/OS。在 cigwin 和 linux SH/BASH/KSH 上,它失败了,这与我的日常 AIX/KSH 相反。所以这是一个“大”限制
      • 我不确定它是否一致,我认为这也可能取决于您尝试执行命令的上下文。经验法则是永远不要尝试写入您正在阅读的同一个文件。
      【解决方案6】:

      xargs:

      printf "%s\n" *.txt | xargs -I FILE -L 1 sed 's/temp/FILE/' FILE
      

      文件名不能有:换行符、斜杠、与号、单引号。

      【讨论】:

        猜你喜欢
        • 2022-11-14
        • 2020-01-30
        • 1970-01-01
        • 2023-03-28
        • 1970-01-01
        • 2018-01-18
        • 2011-08-26
        • 1970-01-01
        • 2021-12-25
        相关资源
        最近更新 更多