Unix 从管道分隔文件中的字符串中删除不匹配的值

Unix 从管道分隔文件中的字符串中删除不匹配的值,unix,awk,Unix,Awk,我有一个输入文件,其中的列由| 输入文件: COL1|COL2 CRIC1|IPL_M1;IPL_M2;TEST_M1 CRIC2|ODI_M1;IPL_M3 CRIC3|ODI_M3;TEST_M5 CRIC4|IPL_M5;ODI_M5;IPL_M;RANGI_M1 CRIC5|RANGI_M1 输出应仅在COL2中更改,其他列不应更改,即在COL2中,应填充具有“IPL_”的字符串, 除“IPL”之外,还需要填充为null并删除不需要的分号。COL2可能包含多达个值(IPL和非IPL值)

我有一个输入文件,其中的列由
|

输入文件:

COL1|COL2
CRIC1|IPL_M1;IPL_M2;TEST_M1
CRIC2|ODI_M1;IPL_M3
CRIC3|ODI_M3;TEST_M5
CRIC4|IPL_M5;ODI_M5;IPL_M;RANGI_M1
CRIC5|RANGI_M1
输出应仅在COL2中更改,其他列不应更改,即在COL2中,应填充具有“IPL_”的字符串, 除“IPL”之外,还需要填充为null并删除不需要的分号。COL2可能包含多达个值(IPL和非IPL值)

预期产出:

COL1|COL2
CRIC1|IPL_M1;IPL_M2
CRIC2|IPL_M3
CRIC3|
CRIC4|IPL_M5;IPL_M6
CRIC5|
我试过这个:

awk -F, -vOFS="|" '{$2=($2!="IPL_%")?" ":$2}1' File.txt

Awk
解决方案:

awk 'BEGIN{ FS = OFS = "|" }
     NR == 1;
     NR > 1{
         len = split($2, a, ";");
         res = "";
         for (i = 1; i <= len; i++)
             if (a[i] ~ /^IPL_/) res = res (res != ""? ";" : "") a[i];
         print $1, res
     }' file.txt

由于所有很酷的awk答案都已被采纳,我开始使用PCRE lookaround,因此,如果您可以使用perl,这里有一个:

perl -p -e 's/(?<=(\|)|(;))[^I][^P][^L][^;\n]*(;|(\n))|/\4/g if $.>1;s/;$//' file
COL1|COL2
CRIC1|IPL_M1;IPL_M2
CRIC2|IPL_M3
CRIC3|
CRIC4|IPL_M5;IPL_M
CRIC5|
输出

COL1|COL2
CRIC1|IPL_M1;IPL_M2
CRIC2|IPL_M3
CRIC3|
CRIC4|IPL_M           # fails if <3 preceeds a match 
CRIC5|

$awk'
开始{FS=OFS=“|”;sfs=“;”}
NR>1{
n=拆分(2美元,f,sfs)
$2 = ""

对于(i=1;i如果
perl
正常:

$ perl -F'\|' -lane '$F[1] = join ";", grep {/IPL_/} split /;/,$F[1] if $.>1;
                     print join "|", @F' ip.txt
COL1|COL2
CRIC1|IPL_M1;IPL_M2
CRIC2|IPL_M3
CRIC3|
CRIC4|IPL_M5;IPL_M
CRIC5|
  • -F'\\'-lane
    有关详细信息,请参见。此处,
    设置为输入字段分隔符,结果可从
    @F
    数组中获得
  • 如果$.>1
    如果输入行号大于1
    • split/;/,$F[1]
    • grep{/IPL\/}
      仅从拆分输出中筛选包含
      IPL\
      的元素。如果需要,请使用正则表达式锚定
    • join”;“
      使用
      连接
      grep
      的输出,然后将结果保存回
      @F
      数组的第二个元素
  • 打印联接“|”、@F
    ,然后打印
    @F
    数组的元素,并使用
    作为分隔符
带有sed

sed -E '
  1b
  s/\|/\|;/
  s/IPL_M/@/g
  s/;[^@][^;]*//g
  s/\|;/\|/
  s/@/IPL_M/g
' infile

另一种
awk
变体:

awk -F '|' '
    NR == 1 { print; next }
    {
        split($2, a, ";")
        s = ""
        for (i = 1; i <= length(a); ++i)
            if (a[i] ~ /^IPL_/)
                s = s a[i] ";"
        print $1, substr(s, 1, length(s)-1)
    }' OFS='|' file

你试过什么吗?试过一个,但不起作用
awk-F,-vOFS=“|”“{$2=($2!=“IPL%”)”?“:$2}1”File.txt
在你的问题中包括你的尝试,并说明它“不起作用”的方式。稍后要发表评论,紧急情况在手。如果你在第二栏中的字段少于3个字符怎么办?)@Sundeep失败。您可以将其简化为
perl-lpe的/(?1;s/;$/”
,但我仍然认为这并不可靠。无论如何,欢迎来到perl世界:D
$ awk '
BEGIN{ FS=OFS="|" } 
{
    n=split($2,a,";")
    for(i=1;i<=n;i++)
        if(a[i]~/^IPL/||NR==1)
            b=b (b==""?"":";") a[i]
    print $1,b;b=""
}' file
COL1|COL2
CRIC1|IPL_M1;IPL_M2
CRIC2|IPL_M3
CRIC3|
CRIC4|IPL_M5;IPL_M
CRIC5|
$ awk '
    BEGIN { FS=OFS="|"; sfs=";" }
    NR>1 {
        n = split($2,f,sfs)
        $2 = ""
        for (i=1; i<=n; i++) {
            if (f[i] ~ /^IPL_/) {
                $2 = ($2=="" ? "" : $2 sfs) f[i]
            }
        }
    }
    { print }
' file
COL1|COL2
CRIC1|IPL_M1;IPL_M2
CRIC2|IPL_M3
CRIC3|
CRIC4|IPL_M5;IPL_M
CRIC5|
$ perl -F'\|' -lane '$F[1] = join ";", grep {/IPL_/} split /;/,$F[1] if $.>1;
                     print join "|", @F' ip.txt
COL1|COL2
CRIC1|IPL_M1;IPL_M2
CRIC2|IPL_M3
CRIC3|
CRIC4|IPL_M5;IPL_M
CRIC5|
sed -E '
  1b
  s/\|/\|;/
  s/IPL_M/@/g
  s/;[^@][^;]*//g
  s/\|;/\|/
  s/@/IPL_M/g
' infile
awk -F '|' '
    NR == 1 { print; next }
    {
        split($2, a, ";")
        s = ""
        for (i = 1; i <= length(a); ++i)
            if (a[i] ~ /^IPL_/)
                s = s a[i] ";"
        print $1, substr(s, 1, length(s)-1)
    }' OFS='|' file
COL1|COL2
CRIC1|IPL_M1;IPL_M2
CRIC2|IPL_M3
CRIC3|
CRIC4|IPL_M5;IPL_M
CRIC5|