【问题标题】:Bash - duplicate lines with different valuesBash - 具有不同值的重复行
【发布时间】:2021-08-10 23:28:50
【问题描述】:

在 Bash 中,我有一个包含以下内容的文件:

05-24-2021,DIS,HostXYZ,   ,,No connection possible,
05-24-2021,DIS,HostABC,BWV ,No connection possible,
06-18-2021,SID,HostWER,SE1  ,No connection possible,
06-18-2021,SID,"Host1:32115,Host2:32115",  ,SOME TEXT,
06-18-2021,SID,HostZZZ,  ,,
06-18-2021,SID,"Host3:32115,Host4:32115",  ,ALSO SOME TEXT,

我想搜索一种方法来复制包含 2 个给定主机的行并将它们分成 2 行,如下所示:

05-24-2021,DIS,HostXYZ,   ,,No connection possible
05-24-2021,DIS,HostABC,BWV ,No connection possible,
06-18-2021,SID,HostWER,SE1  ,No connection possible,
06-18-2021,SID,Host1,  ,SOME TEXT,
06-18-2021,SID,Host2,  ,SOME TEXT,
06-18-2021,SID,HostZZZ,  ,,
06-18-2021,SID,Host3,  ,ALSO SOME TEXT,
06-18-2021,SID,Host4,  ,ALSO SOME TEXT,

也许你有任何改变它的想法?我真的很感激。我用 awk、sed 等进行了尝试。我能够复制(使用“sed 's/:/:/p'”)至少受影响的行,但不能“过滤掉”特定值。

【问题讨论】:

  • 输入中是否有文字**?这听起来像你只是想解析一个伪csv,它在一些用双引号表示的列中具有分隔符。
  • 如果适合您的问题,请不要忘记将答案标记为已接受。

标签: awk sed duplicates


【解决方案1】:

使用 GNU awk 获取 FPAT:

$ cat tst.awk
BEGIN {
    FPAT = "[^,]*|\"[^\"]*\""
    OFS = ","
}
$3 ~ /,/ {
    gsub(/"/,"",$3)
    n = split($3,hosts,/,/)
    for (i=1; i<=n; i++) {
        sub(/:.*/,"",hosts[i])
        $3 = hosts[i]
        print
    }
    next
}
{ print }

$ awk -f tst.awk file
05-24-2021,DIS,HostXYZ,   ,,No connection possible,
05-24-2021,DIS,HostABC,BWV ,No connection possible,
06-18-2021,SID,HostWER,SE1  ,No connection possible,
06-18-2021,SID,Host1,  ,SOME TEXT,
06-18-2021,SID,Host2,  ,SOME TEXT,
06-18-2021,SID,HostZZZ,  ,,
06-18-2021,SID,Host3,  ,ALSO SOME TEXT,
06-18-2021,SID,Host4,  ,ALSO SOME TEXT,

如果您要使用 awk 进行更复杂的 CSV 解析,请参阅 What's the most robust way to efficiently parse CSV using awk?

【讨论】:

    【解决方案2】:

    awk 试试这个是一个非常糟糕的主意。使用适当的 csv 解析器。但是,虽然它很脆弱,但您可以尝试:

    awk 'NF<2; NF>2{n=split($2,a,","); 
        for(i=1;i<=n;i++) printf("%s,%s,%s\n", $1,a[i],$3)}'  FS=\" input
    

    【讨论】:

      【解决方案3】:

      如果每行最多有两个主机,用双引号括起来,一个简单的方法是使用捕获组获取重复项:

      sed -r 's/^(.*)"(Host[^":]*):[^",]*,(Host[^":]*):[^",]*"(.*)$/\1\2\4\n\1\3\4/'
      

      正则表达式:

      • s/a/b/:用b 替换a 正则表达式匹配的文本
      • ^(.*)":捕获行首直到出现双引号(第 1 组)
      • (Host[^":]*):[^",]*,(Host[^":]*):[^",]*":在双引号后找到描述两个主机并以双引号结尾的文本;捕获每个主机名(第 2 组和第 3 组)
      • (.*)$: 捕获该行的剩余文本

      替换:将匹配的行替换为两行(以行尾分隔 \n),以捕获的文本 1 开头,然后是捕获的文本 2 第一行和3 第二个;以最后捕获的文本4 结束每一行,即匹配行的剩余文本。

      此答案取决于您提供的示例。它不会涵盖无数的边缘情况。

      【讨论】:

        【解决方案4】:

        awk,你可以这样做:

        awk 'BEGIN{FS="\""} 
          (NF == 1) {print}
          (NF > 2) {
            split($2, h, ","); 
            for (i = 1; i <= 2; i++) {
              gsub(/:[0-9]*/, ",", h[i]); 
              print $1 h[i] $3
            }
          }' input
        

        【讨论】:

          猜你喜欢
          • 2019-06-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-09-03
          • 1970-01-01
          • 2017-03-02
          • 2015-08-09
          • 1970-01-01
          相关资源
          最近更新 更多