如何通过给定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 ] && 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中另一个文件中的列来从文件中删除列?的主要内容,如果未能解决你的问题,请参考以下文章