如何打印包含值的列

时间:2015-02-11 04:20:54

标签: awk sed grep

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

 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     

如果代码并不需要我知道列和/或行的确切数量,那就太棒了。

3 个答案:

答案 0 :(得分:2)

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

$ 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]对于任何列为{0}的列i设置为1。

    由于条件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非{0}的每列a[i]。我选择了制表符分隔输出,但只需调整printf语句,就可以使用任何格式。

答案 1 :(得分:1)

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:]]*\)/\2>\1/g
# remove treated column
   s/>[[:blank:]]*[0-9]\{1,\}\([[:blank:]]\{1,\}[[:graph:][:blank:]]*\)/>\1/g
# is there another colum to treat ?
   />[[:blank:]]*[0-9][[:graph:][:blank:]]/ b cycle

# print result after cleanup
   s/>//gp
   }' YourFile
  • 自评评sed
  • posix versioj所以--posix关于GNU sed

答案 2 :(得分:0)

这是使用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 $1
}

像这样运行它,例如:

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