【问题标题】:Removing column in pipe delimited file when the text matches with search string当文本与搜索字符串匹配时删除管道分隔文件中的列
【发布时间】:2014-10-28 06:40:20
【问题描述】:

我需要在管道分隔文件中搜索特定文本并删除与该文本匹配的列。

例如: 我的档案

1|2|test123|3|4|5....|n
6|7|5|test123|10|11.....|n
6|7|1|9|test123|11.....|n

需要搜索包含“test”的列并删除该列

新文件应该是这样的

1|2|3|4|5....|n
6|7|5|10|11.....|n
6|7|1|9|11.....|n

我试过了

awk 'BEGIN{FS=OFS="|"}{$2=$3="";gsub(/[|]+/,"|")}1' test.txt >> test5.txt

列号被明确硬编码但需要一个脚本来搜索文本然后删除列的命令。

【问题讨论】:

    标签: unix


    【解决方案1】:

    文件.txt

    1|2|test123|3|4|5....|n
    6|7|5|test123|10|11.....|n
    6|7|1|9|test123|11.....|n
    

    脚本:

    sed 's/test123|//' file.txt >> file1.txt
    

    【讨论】:

    • Nit Picking:只删除包含test123 而不仅仅是test 的列;当test123(或test)不在字段末尾时,不会删除它们;当字段中有除test123(或test)以外的额外字符时,不会删除整个字段;不会从该行的最后一个字段中删除它。
    【解决方案2】:

    所有示例均使用数据文件:

    1|2|test123|3|4|5....|n
    6|7|5|test123|10|11.....|n
    6|7|1|9|test123|11.....|n
    test|1|2|3|4|5......|n
    1|2|3|4|5|6.....|n-test-n
    1|2|test|and-test-again|3|4|5|6.....|n-test-n
    

    至少有两种方法可以解决这个问题。一个是纯文本的:用一个管道替换一个序列管道、零个或多个非管道、单词“test”、零个或多个非管道以及另一个管道:

    awk '{ gsub(/\|[^|]*test[^|]*\|/, "|"); print }' test.txt >> test5.txt
    

    输出:

    1|2|3|4|5....|n
    6|7|5|10|11.....|n
    6|7|1|9|11.....|n
    test|1|2|3|4|5......|n
    1|2|3|4|5|6.....|n-test-n
    1|2|and-test-again|3|4|5|6.....|n-test-n
    

    鉴于“测试”一词可能出现在第一列或最后一列,您必须更加努力地处理这些问题:

    awk '{ gsub(/\|[^|]*test[^|]*\|/, "|");  # Middle
           gsub(/^[^|]*test[^|]*\|/, "");    # Start
           gsub(/\|[^|]*test[^|]*$/, "");    # End
           print }' test.txt >> test5.txt
    

    输出:

    1|2|3|4|5....|n
    6|7|5|10|11.....|n
    6|7|1|9|11.....|n
    1|2|3|4|5......|n
    1|2|3|4|5|6.....
    1|2|and-test-again|3|4|5|6.....
    

    鉴于test 可以出现在相邻字段中,您必须扫描两次以查找“中间”模式。

    awk '{ gsub(/\|[^|]*test[^|]*\|/, "|");  # Middle - 1
           gsub(/\|[^|]*test[^|]*\|/, "|");  # Middle - 2
           gsub(/^[^|]*test[^|]*\|/, "");    # Start
           gsub(/\|[^|]*test[^|]*$/, "");    # End
           print }' test.txt >> test5.txt
    

    输出:

    1|2|3|4|5....|n
    6|7|5|10|11.....|n
    6|7|1|9|11.....|n
    1|2|3|4|5......|n
    1|2|3|4|5|6.....
    1|2|3|4|5|6.....
    

    另一种方式是扫描每一行的字段,而不是打印那些包含“test”的字段。

    awk -F '|' \
        '{ pad = "";
           for (i = 1; i <= NF; i++)
           {
             if ($i !~ /test/)
             {
               printf("%s%s", pad, $i);
               pad = "|";
             }
           }
           print "";
         }' test.txt >> test5.txt
    

    输出:

    1|2|3|4|5....|n
    6|7|5|10|11.....|n
    6|7|1|9|11.....|n
    1|2|3|4|5......|n
    1|2|3|4|5|6.....
    1|2|3|4|5|6.....
    

    【讨论】:

    • awk -F '|' \'{垫=“”; for (i = 1; i
    • 在脚本结束之后,所以在结束单引号之后。你有awk &lt;options&gt; &lt;script&gt; &lt;files&gt;(一般来说)。我现在更新了答案以包含您的文件名和输出重定向。
    • 优秀的作品很好。我还需要删除第 i 列之后的下一列,即具有“测试”的列
    • 因此,当您在带有循环的版本中检测到test 时,也可以通过将(新添加的)else 子句中的i 递增到if 语句中来跳过下一列:@ 987654336@。这会导致双倍增量,也跳过了以下列。你也可以用gsub() 代码来做,但它更混乱(如果测试出现在最后一列会发生什么?)。
    • 根据要求测试不会是最后一列。你能给我完整的代码片段和下一列逻辑吗?
    猜你喜欢
    • 2018-10-21
    • 2015-01-18
    • 1970-01-01
    • 2020-06-17
    • 1970-01-01
    • 1970-01-01
    • 2019-01-27
    • 2017-07-04
    • 1970-01-01
    相关资源
    最近更新 更多