如何通过给定Linux中另一个文件中的列来从文件中删除列?

Posted

技术标签:

【中文标题】如何通过给定Linux中另一个文件中的列来从文件中删除列?【英文标题】:How to remove columns from a file by given the columns in anther file in Linux? 【发布时间】:2022-01-21 06:24:18 【问题描述】:

假设我有一个文件 A 包含需要删除的列号(我的输入文件 fileB 中确实有超过 500 列),

文件A:

2
5

我想从 fileB 中删除这些列(2 和 5):

a b c d e f
g h i j k l

在 Linux 中获取:

a c d f
g i j l

我该怎么办?我发现我可以消除使用代码打印这些列:

awk '$2=$5="";print $0' fileB

但是,这种方式有两个问题,首先它并没有真正删除那些列,它只是使用空字符串来替换它们;其次,我如何通过从另一个文件中读取来获取这些列号,而不是手动输入这些列号。


原问题: 假设我有一个文件 A 包含需要删除的列号,

文件 A:

223 345 346 567

我想从 Linux 中的文件 B 中删除这些列 (223, 345,567),我该怎么办?

【问题讨论】:

请添加到您的问题中(无评论):您搜索了什么,找到了什么?您尝试过什么,它是如何失败的? 我发现我可以消除使用代码打印这些列:awk '$223=$345=$346=$567="";print $0' fileB,但是,这里有两个问题方式,首先它并没有真正删除这些列,它只是使用空字符串来替换它们;其次,我怎样才能通过从另一个文件中读取来获取这些列号,而不是手动输入这些列号。 将该信息添加到您的问题中,不要将其放在无法格式化且可能遗漏的评论中。谈到格式化,请使用来自***.com/help/formatting 的“代码块”信息来格式化您的示例输入、预期输出和代码。 我们不想看到超过 567 列的示例。请创建并发布一个minimal reproducible example,其中包含 6 个列,您想删除其中的 2 个。一旦你得到了答案,你就可以将同样的技术应用到你的实际问题中。 我编辑了您的问题,向您展示如何在此论坛上提出可接受的问题。 【参考方案1】:

如果您的cut--complement 选项,那么您可以这样做:

cut --complement -d ' ' -f "$(echo $(<FileA))" fileB

【讨论】:

嗨,Fravadona,我试过这种方式,但它给了我错误,剪切:2:没有这样的文件或目录剪切:3:没有这样的文件或目录 我的错,修好了 它现在工作了!谢谢! 不错的答案,应该很有效率。 @MengnaZhang 我会在运行命令之前测试 FileA:[ -s FileA ] &amp;&amp; cut --complement ...【参考方案2】:
$ cat tst.awk
NR==FNR 
    badFldNrs[$1]
    next

FNR == 1 
    for (inFldNr=1; inFldNr<=NF; inFldNr++) 
        if ( !(inFldNr in badFldNrs) ) 
            out2in[++numOutFlds] = inFldNr
        
    


    for (outFldNr=1; outFldNr<=numOutFlds; outFldNr++) 
        inFldNr = out2in[outFldNr]
        printf "%s%s", $inFldNr, (outFldNr<numOutFlds ? OFS : ORS)
    

$ awk -f tst.awk fileA fileB
a c d f
g i j l

【讨论】:

非常好。保存你想要的,跳过那些你不想要的。 @DavidC.Rankin 对,这样如果你想输出 100 个字段中的 10 个,那么主循环迭代 10 次而不是像 markp-fuso's answer 和 HatLess's answer 那样迭代 100 次。我认为,由于 OP 有超过 500 个字段和一个完整的字段文件来跳过效率可能很重要。 @EdMorton - 这是一个(不是那么)微妙的点,直到你发表评论我才知道。一个放置得当的评论永远不会伤害到强调一个重要的点,乍一看可能已经逃过了那些慢吞吞的老家伙们。 @DavidC.Rankin 我觉得我大约每周发布一次这种代码,我只是懒得解释为什么,直到有人遇到它。【参考方案3】:

一个awk想法:

awk '
FNR==NR  skip[$1] ; next                 # store field #s to be skipped
         line=""                          # initialize output variable
          pfx=""                           # first prefix will be ""
          for (i=1;i<=NF;i++)              # loop through the fields in this input line ...
              if ( !(i in skip) )         # if field # not mentioned in the skip[] array then ...
                 line=line pfx $i          # add to our output variable
                 pfx=OFS                   # prefix = OFS for 2nd-nth fields to be added to output variable
              
          if ( pfx == OFS )                # if we have something to print ...
             print line                    # print output variable to stdout
         
' fileA fileB

注意: OP 没有提供输入/输出字段分隔符; OP 可以根据需要添加适当的FS/OFS 分配

这会生成:

a c d f
g i j l

【讨论】:

【参考方案4】:

使用awk

$ awk 'NR==FNR col[$1]=$1;next for(i=1;i<=NF;++i) if (i != col[i]) printf("%s ", $i);  printf("\n")' fileA fileB
a c d f
g i j l

【讨论】:

有效!非常感谢!

以上是关于如何通过给定Linux中另一个文件中的列来从文件中删除列?的主要内容,如果未能解决你的问题,请参考以下文章

如何通过比较两个表中的两列来更新表中的列

如何通过使用数据框中的其他列来聚合熊猫数据框中的列

如何通过在 MATLAB 中模板化 2D 数组的列来创建 3D 数组?

如何优化查询以使用oracle中另一个表中的列更新表列

如何使用laravel中另一个表中的外键获取所需的列

如何根据一个数据帧中的列值和R中另一个数据帧的列标题名称有条件地创建新列