【问题标题】:Replacing strings in files with bash sed or a scripting language (TCL, perl)用 bash sed 或脚本语言(TCL、perl)替换文件中的字符串
【发布时间】:2014-07-30 22:54:09
【问题描述】:

我有一个 C++ 源文件列表,其结构如下:

// A lot of stuff
#include <current/parser/support/base.hpp>
// ...
#include <current/parser/iterators/begin.hpp>
// ...

我需要替换像

这样的行
#include <current/parser/support/base.hpp>

#include <support_base.hpp>

即,省略 current/parser 并将分隔符 (/) 替换为 _。 这可能与 bash sed 或脚本语言有关吗?

编辑:对不起,忘了说我想替换类似的东西

#include <current/parser/*/*/*/*>

current/parser 之后任何事情都可以进行,而且深度不限。

【问题讨论】:

  • sed 可以做到,但您应该记住,使用这些工具 (sed/awk...) 来“修复”您的源代码可能会带来新问题。这是有风险的。
  • 您想只替换那些包含current/parser 的行还是所有包含#include &lt;anypath/last/file.hpp&gt; 的行?
  • 已编辑。以 #include 开头的任何内容
  • 那么鉴于您当前编辑的示例,您希望#include &lt;*_*_*_*&gt; 作为输出?

标签: perl bash shell sed tcl


【解决方案1】:

使用 perl 单行代码

perl -i -pe 's{^#include <\Kcurrent/parser/([^>]*)}{$1 =~ y|/|_|r}e;' file.cpp

或者没有大于 perl 5.10 的正则表达式功能

perl -i -pe 's{(?<=^#include <)current/parser/([^>]*)}{join "_", split "/", $1}e;' file.cpp

说明:

开关

  • -i:就地编辑文件(如果提供扩展名,则进行备份)
  • -p:为输入文件中的每一行创建一个 while(&lt;&gt;){...; print} 循环。
  • -e:告诉perl 在命令行上执行代码。

【讨论】:

    【解决方案2】:

    使用 sed:

    sed -i -e '/#include <current\/parser\/support\/base\.hpp>/{ s|current/parser/||; s|/|_|; }' -- file1 file2 file3
    

    编辑:

    sed -i -e '/#include <current\/parser\/.*>/{ s|current/parser/||; s|/|_|g; }' -- file1 file2 file3
    

    将删除 currrent/parsers/ 并将所有 / 替换为 _。示例结果文件:

    // A lot of stuff
    #include <support_base.hpp>
    // ...
    #include <iterators_begin.hpp>
    // ...
    

    一些细节:

    /#include <current\/parser\/.*>/  --  Matcher.
    s|current/parser/||               --  Deletes `current/parser/` in matched line.
    s|/|_|g                           --  Replaces all `/` with `_` in same line.
    

    【讨论】:

    • 非常好的方法,我特别喜欢处理所有数量的/{} 块。此外,一个小的解释可以帮助人们更好地理解它。
    【解决方案3】:

    你可以用sed-r试试正则表达式:

    sed -r 's|#include <current/parser/support/base\.hpp>|#include <support_base.hpp>|g' file
    

    但是使用这种方式可能会杀死您的代码。所以要小心:)

    【讨论】:

    • Errr 但这是硬编码的,不是吗? iterators/begin.hpp呢?
    • 另外,关于它如何杀死代码的更多描述会很好。顺便说一句,正则表达式中的. 几乎匹配任何字符。 sed 有什么不同吗?
    • 感谢@Jerry 的提示,忘记转义了 :)
    【解决方案4】:

    使用 Tcl:

    # Open the file for reading
    set fin [open filein.c r]
    # Open the file to write the output
    set fout [open fileout.c w]
    
    # Loop through each line
    while {[gets $fin line] != -1} {
        # Check for lines beginning with "^#include <current/parser/"
        #
        # ^ matches the beginning of the line
        # ([^>]*) matches the part after "#include <current/parser/" and stores it
        #    in the variable 'match'
    
        if {[regexp {^#include <current/parser/([^>]*)>} $line - match]} {
            # the edited line is now built using the match from above after replacing
            #    forward slashes with underscores
            set newline "#include <[string map {/ _} $match]>"
        } else {
            set newline $line
        }
        # Put output to the file
        puts $fout $newline
    }
    
    # Close all channels
    close $fin
    close $fout
    

    使用提供的输入输出:

    // A lot of stuff
    #include <support_base.hpp>
    // ...
    #include <iterators_begin.hpp>
    // ...
    

    Demo on codepad(我稍微编辑了代码,因为我无法打开通道来读取/写入那里的文件)

    【讨论】:

      猜你喜欢
      • 2022-07-21
      • 2011-08-28
      • 2017-09-06
      • 2019-08-24
      • 2017-11-17
      • 2015-11-18
      • 1970-01-01
      • 1970-01-01
      • 2012-04-21
      相关资源
      最近更新 更多