Its*_*hng 6 sed awk patterns columns
我正在寻找一个选项来删除具有特定文本的列,例如
“滴滴”
aaa bbb ccc ddd eee fff
1 2 3 4 5 6
2 3 4 5 6 0
Run Code Online (Sandbox Code Playgroud)
所以输出看起来像这样:
aaa bbb ccc eee fff
1 2 3 5 6
2 3 4 6 0
Run Code Online (Sandbox Code Playgroud)
我知道有一个简单的选项可以删除第 4 列并且可以完成相同的工作,但是我的 *.csv 文件没有排序。有任何想法吗?
sed
不是正确的工具。尝试awk
:
$ awk -v OFS='\t' 'NR==1{for (i=1;i<=NF;i++)if ($i=="ddd"){n=i-1;m=NF-(i==NF)}} {for(i=1;i<=NF;i+=1+(i==n))printf "%s%s",$i,i==m?ORS:OFS}' file
aaa bbb ccc eee fff
1 2 3 5 6
2 3 4 6 0
Run Code Online (Sandbox Code Playgroud)
这假设要删除的字符串ddd
在这种情况下显示为第一行中的字段。
-v OFS='\t'
这将输出字段分隔符设置为选项卡。如果您正在使用其他东西,请更改此设置。
NR==1{for (i=1;i<=NF;i++)if ($i=="ddd"){n=i-1;m=NF-(i==NF)}}
这将扫描第一行中的所有列。我们将带有ddd
(减一)的列数保存在变量 中n
。
它还设置m
为最后一列的编号,除非i
是最后一列,在这种情况下它将其设置为NF-1
。
for(i=1;i<=NF;i+=1+(i==n))printf "%s%s",$i,i==m?ORS:OFS
这会打印出每个字段,跳过ddd
出现在第一行中的字段。
i+=1
将i
在每个循环中递增1。 在每个循环中i+=1+(i==n)
递增i
1,除非i==n
在这种情况下i
递增 2。这具有跳过右列的效果。
printf "%s%s",$i,i==m?ORS:OFS
打印列i
后跟列分隔符OFS
或行分隔符ORS
,具体取决于是否i
是最后一列。
对于那些喜欢这样写成多行命令的人:
awk -v OFS='\t' '
NR==1{
for (i=1;i<=NF;i++)
if ($i=="ddd") {
n=i-1
m=NF-(i==NF)
}
}
{
for(i=1;i<=NF;i+=1+(i==n))
printf "%s%s",$i,i==m?ORS:OFS
}
' file
Run Code Online (Sandbox Code Playgroud)
如果我们希望输入和输出以逗号分隔,我们需要同时更改输入字段分隔符(带-F
)和输出字段分隔符。例如,考虑这个输入文件:
$ cat file2
aaa,bbb,ccc,ddd,eee,fff
1,2,3,4,5,6
2,3,4,5,6,0
Run Code Online (Sandbox Code Playgroud)
然后使用:
$ awk -F, -v OFS=, 'NR==1{for (i=1;i<=NF;i++)if ($i=="ddd"){n=i-1;m=NF-(i==NF)}} {for(i=1;i<=NF;i+=1+(i==n))printf "%s%s",$i,i==m?ORS:OFS}' file2
aaa,bbb,ccc,eee,fff
1,2,3,5,6
2,3,4,6,0
Run Code Online (Sandbox Code Playgroud)
这在sed
(大多数情况下)是可能的,但我怀疑它比使用其他工具更简单。最简单的方法是首先获取您想要的字段编号,然后通过文件打印其余部分。例如,在 Perl 中:
$ perl -lane 'if($.==1){for(0..$#F){$d=$_ if $F[$_] eq "ddd"}}
print "@F[0..$d-1] @F[$d+1..$#F]"' file
aaa bbb ccc eee fff
1 2 3 5 6
2 3 4 6 0
Run Code Online (Sandbox Code Playgroud)
然而,这搞砸了格式。如果这很重要,请改用 John1024 的答案。