我有一个文本文件 temp1 并说它有 20 多列,它的数值如下所示,
1,0,3,0,5........,
1,0,5,0,8........,
3,0,6,0,3........,
5,0,6,0,4........,
.................,
我想删除总和为零的列,我需要将剩余的列重定向到新文件
即:例如上面第 2 列和第 4 列的总数为零,因此我需要删除第 2 列和第 4 列并将其重定向到单独的文件。
有人可以帮我吗?
$ cat file
1,0,3,0,5
1,0,5,0,8
3,0,6,0,3
5,0,6,0,4
$ awk -f tst.awk file
1,3,5
1,5,8
3,6,3
5,6,4
$ cat tst.awk
BEGIN{ FS="," }
{
for (j=1;j<=NF;j++) {
val[NR,j] = $j
sum[j] += val[NR,j]
}
}
END {
for (i=1;i<=NR;i++) {
ofs = ""
for (j=1;j<=NF;j++) {
if (sum[j]) {
printf "%s%s",ofs,val[i,j]
ofs = FS
}
}
print ""
}
}
这是使用awk
. 像这样运行:
awk -f ./script.awk file{,}
内容script.awk
:
BEGIN {
FS=","
}
FNR==NR {
for(i=1;i<=NF;i++) {
if ($i != 0) {
a[i]
}
}
next
}
{
for(j=1;j<=NF;j++) {
if (j in a) {
printf "%s%s", $j, (j==NF ? RS : FS)
}
}
}
或者,这是单线:
awk -F, 'FNR==NR { for(i=1;i<=NF;i++) if ($i != 0) a[i]; next } { for(j=1;j<=NF;j++) if (j in a) printf "%s%s", $j, (j==NF ? RS : FS) }' filex{,}
内容file
:
1,0,3,0,5,0
1,0,5,0,8,1
3,0,6,0,3,2
5,0,6,0,4,5
结果:
1,3,5,0
1,5,8,1
3,6,3,2
5,6,4,5
您可以使用 awk :(以下内容很难看,但我希望可读。这就是目标。我让更好的 awkist 进一步增强/减少它)
如果数据在文件中/path/to/zefile
:
awk -F',' '
FNR==NR { for (col=1;col<=NF;col++)
{ if ($col != 0)
{wewantthiscolumn[col]=1 }
}
next
}
{ for (col=1;col<=NF;col++)
{ if (wewantthiscolumn[col]==1)
{ printf ("%s,",$col) }
}
print ""
}' /path/to/zefile /path/to/zefile | sed -e 's/,$//'
这个想法:我们在 /path/to/zefile /path/to/zefile 上启动 awk(因此,它读取了两次)。
在第一遍中,我们创建了一个“wewantthiscolumn”数组。只要该列与 0 不同,该数组就包含“1”。“下一个”确保我们仅在 FNR(=当前文件中的行数)== NR(=总行数)时执行此位,这仅在第一次通过时是正确的。
在第二遍(因此我们直接进入第二个 { } ,因为现在 NR>FNR):我们只显示$col
具有对应的列值wewantthiscolumn(col)==1
,然后是一个“,”(所以有一个小问题:最后一个列后面会有一个“,”)
然后我们通过 sed 传递它以去掉 ",$" 位。
我不确定有没有更好的方法:awk 可以删除一个字段吗?所以它可以在第二遍删除字段 col 吗?然后打印结果 $0 会容易得多,设置OFS=','
为将它们与,
...分开
这将使第二次通过:
awk -F',' '
FNR==NR { for (col=1;col<=NF;col++)
{ if ($col != 0)
{wewantthiscolumn[col]=1 }
}
next
}
{ for (col=1;col<=NF;col++)
{ if (wewantthiscolumn[col]==0)
$col="DELETETHIS"
}
gensub(",DELETETHIS","",g)
gensub("DELETETHIS,","",g)
print $0
}' /path/to/zefile /path/to/zefile
我不想假设没有列可以是空的,因此我使用“DELETETHIS”来确保我只删除相关字段......但这意味着第一种方式实际上更简单^^:只打印你需要的字段,然后去掉行尾的“,”。
使用python的解决方案:
#!/usr/bin/env python
def transpose(grid):
return zip(*grid)
def removeBlankRows(grid):
return [list(row) for row in grid if any(map(int,row))]
grid = []
with open("input.csv") as fd:
for line in fd:
grid.append(line.strip().split(','))
data = removeBlankRows(transpose(removeBlankRows(transpose(grid))))
for i in data:
print ",".join(i)
输入:
1,0,3,0,5
1,0,5,0,8
3,0,6,0,3
5,0,6,0,4
输出:
1,3,5
1,5,8
3,6,3
5,6,4
输入:
1,0,3,0,5
1,0,5,0,8
3,0,6,0,3
5,0,6,1,4
输出:
1,3,0,5
1,5,0,8
3,6,0,3
5,6,1,4