如何打印包含值的列

How to print columns containing value

假设我有一个包含以下内容的数据文件:

 1     2     3     4     5
67    88    12    32    22
 9    99    34    59    86
17     0    78     0    77
11     0     0     0    43

我想要一个代码在每一列中搜索数字 0。如果找到数字 0,该代码将在一个单独的文件中打印出整列。

使用这些数据,输出的文件将如下所示:

 2     3     4
88    12    32
99    34    59
 0    78     0
 0     0     0     

如果代码不需要我知道 and/or 行的确切列数,那就太好了。

这会做你想做的。它不需要知道有多少行或列。

$ awk 'FNR==NR{for (i=1;i<=NF;i++)if ($i==o)a[i]=1;next} {tab="";for (i=1;i<=NF;i++)if (a[i]){printf "%s%s",tab,$i; tab="\t"};print ""}' file file
2       3       4
88      12      32
99      34      59
0       78      0
0       0       0

工作原理

因为文件名在命令行中指定了两次,所以awk脚本将读取文件两次,第一次查找零,第二次打印。

  • FNR==NR{for (i=1;i<=NF;i++)if ($i==o)a[i]=1;next}

    通过文件的第一个 运行,a[i] 被设置为任何包含零的列 i

    由于条件 FNR==NR,此代码仅适用于第一个 运行。 NR 是我们到目前为止已经读取的记录总数(行)。 FNR 是我们到目前为止从当前文件中读取的记录(行)数。因此,当FNR==NR时,我们仍在读取第一个文件。命令末尾的 next 告诉 awk 跳过剩余的命令并从下一行开始。

  • tab="";for (i=1;i<=NF;i++)if (a[i]){printf "%s%s",tab,$i; tab="\t"};print ""

    当我们第二次读取文件时,我们打印出 i 的每一列 a[i] 是非零的。我选择了制表符分隔的输出,但是通过简单地调整 printf 语句,可以使用任何格式。

sed '#n
# init and load line in buffer (1st line copied, other added)
s/.*/>& /;1!H;1h

# at end of file, load buffer in working area
$ {x
:cycle
# keep column if zero inside
   />[[:blank:]]*0[[:blank:]]/ s/>\(\([[:blank:]]*[0-9]\{1,\}\)[[:blank:]][[:graph:][:blank:]]*\)/>/g
# remove treated column
   s/>[[:blank:]]*[0-9]\{1,\}\([[:blank:]]\{1,\}[[:graph:][:blank:]]*\)/>/g
# is there another colum to treat ?
   />[[:blank:]]*[0-9][[:graph:][:blank:]]/ b cycle

# print result after cleanup
   s/>//gp
   }' YourFile
  • 的自我评论
  • posix 版本为 --posix 在 GNU 上为

这里有一个使用 GNU awk 的有趣方法:

parse.awk

# Record number of columns (assuming all columns have the same number of fields)
NR == 1 { n = NF } 

# First parse: Remember which columns contain `pat`
FNR == NR { 
  for(i=1; i<=NF; i++) 
    if($i == pat) {
      h[i] = i
      last = i>last ? i : last
    }
  next
} 

# Before second parse: switch to reading one field at a time
ENDFILE { 
  RS="[ \t\n]+"
} 

# Second parse: print field if current-record-number modulo 
#               number-of-columns is in the `h` hash
{ m = FNR % n }

m in h {
  ORS = (m == last) ? "\n" : OFS  # print new-line after last column
  print 
}

运行 例如:

awk -f parse.awk pat=0 infile infile

输出:

2 3 4
88 12 32
99 34 59
0 78 0
0 0 0

OFS='\t':

awk -f parse.awk pat=0 OFS='\t' infile infile

输出:

2   3   4
88  12  32
99  34  59
0   78  0
0   0   0