Unix 当文本与搜索字符串匹配时删除管道分隔文件中的列

Unix 当文本与搜索字符串匹配时删除管道分隔文件中的列,unix,Unix,我需要在管道分隔文件中搜索特定文本,并删除与文本匹配的列 例: 我的档案 需要搜索包含“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 命令,其中列号是显式硬编码的,但需要一个脚本来搜索文本,然后删除列。所有示例都使用数据

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

例: 我的档案

需要搜索包含“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

命令,其中列号是显式硬编码的,但需要一个脚本来搜索文本,然后删除列。

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

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
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.....
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.....
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 '{ 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
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
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.....
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.....
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 '{ 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
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
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.....
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.....
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
file.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

挑剔:只删除包含
test123
的列,而不只是
test
;当
test123
(或
test
)不在字段末尾时,不删除它们;当字段中除了
test123
(或
test
)之外还有其他字符时,不删除整个字段;不将其从.awk-F'|'\'{pad=”“;for(i=1;i在脚本结束后,所以在结束单引号后)行的最后一个字段中删除。您有
awk
(通常)。我现在已经更新了答案,以包括您的文件名和输出重定向。非常好。我还需要删除第I列之后的下一列,即具有“Test”的列,因此当您在带有循环的版本中检测到
Test
时,也可以通过在(新添加的)中增加
I
跳过下一列
else
子句添加到
if
语句:
else i++
。这会导致一个双倍增量,也会跳过下一列。您也可以使用
gsub()
代码来执行,但它更混乱(如果最后一列中出现test,会发生什么情况?)根据需求测试不会是最后一列。你能给我下一列逻辑的完整代码片段吗。