Awk 数组中的最后一项未从循环中显示

Awk 数组中的最后一项未从循环中显示,awk,Awk,数组的最后一项无法从循环中正确打印 在学习shell文本过滤器时,我编写了一个小awk脚本,通过提供内联标题来格式化CSV文件的输出 从命令行调用包装器shell脚本,它真正做的就是包装awk脚本,并将参数作为变量regex传递,该变量是搜索字符串 脚本将第一条记录的字段(NR==1)存储到数组标题中。一旦在CSV文件正文中找到包含搜索字符串regex的记录,脚本就会将标题连接到适当的值 csv.sh: #/bin/bash awk-f~/Scripts/csv.awk-v“regex=$1”$

数组的最后一项无法从循环中正确打印

在学习shell文本过滤器时,我编写了一个小awk脚本,通过提供内联标题来格式化CSV文件的输出

从命令行调用包装器shell脚本,它真正做的就是包装awk脚本,并将参数作为变量
regex
传递,该变量是搜索字符串

脚本将第一条记录的字段(
NR==1
)存储到数组
标题中。一旦在CSV文件正文中找到包含搜索字符串
regex
的记录,脚本就会将标题连接到适当的值

csv.sh:

#/bin/bash
awk-f~/Scripts/csv.awk-v“regex=$1”$2
csv.awk:

BEGIN {FS=",";}
NR==1 { 
  for (i=1; i<=NF; i++) { 
    heading[i]=$i; 
  } 
}
NR>1 {
  if ($0 ~ regex) {
    for (i=1; i<=length(heading); i++) {
      if(length($i) > 0) { 
        print(heading[i] ": " $i)
      } 
    }
    print("")
  }
}
调用
$csv Enterprise ships.csv

预期产量 终端输出: 在我的Linux计算机(Manjaro)上,输出非常相似。但实际上,如果我在Mac上通过管道将输出传输到
pbcopy
,粘贴后标题确实会显示出来:

name: USS Enterprise
country: United States of America
displacement: 19800
length: 251.4
beam: 33.4
commissioned
: 12 May 1938

将数组传递给
length
函数是无效的

如果您怀疑某个混乱的csv文件的标题可能与实际列不匹配,那么,一个可移植的选项是在开头存储总列数,然后按如下方式重新使用:

NR==1 { 
  headercount=NF; # store the count
  for (i=1; i<=NF; i++) { 
    heading[i]=$i; 
  } 
}
NR>1 {
  if ($0 ~ regex) {
    for (i=1; i<=headercount; i++) { #Use the count
      if(length($i) > 0) {
        print(heading[i] ": " $i)
      }
    }
    print("")
  }
}
测试

$ ./csv.sh HMS ships.csv 
name: HMS Dreadnought
country: United Kingdom
displacement: 18120
length: 160.6
beam: 25
commissioned: 2 December 1906

name: HMS Vanguard
country: United Kingdom
displacement: 45200
length: 248.2
beam: 32.9
commissioned: 12 May 1946
$ ./csv.sh HMS ships.csv 
name: HMS Dreadnought
country: United Kingdom
displacement: 18120
length: 160.6
beam: 25

name: HMS Vanguard
country: United Kingdom
displacement: 45200
length: 248.2
beam: 32.9
如果你的标题被篡改了,所以他们没有,比如说,委托的列,这也会在那个场景中无缝地工作

测试

$ ./csv.sh HMS ships.csv 
name: HMS Dreadnought
country: United Kingdom
displacement: 18120
length: 160.6
beam: 25
commissioned: 2 December 1906

name: HMS Vanguard
country: United Kingdom
displacement: 45200
length: 248.2
beam: 32.9
commissioned: 12 May 1946
$ ./csv.sh HMS ships.csv 
name: HMS Dreadnought
country: United Kingdom
displacement: 18120
length: 160.6
beam: 25

name: HMS Vanguard
country: United Kingdom
displacement: 45200
length: 248.2
beam: 32.9

根据格伦的评论,你能试试下面的吗

awk 'BEGIN {FS=",";}
{gsub(/\r/,"")}
NR==1 { 
  for (i=1; i<=NF; i++) { 
    heading[i]=$i; 
  } 
}
NR>1 {
  if ($0 ~ regex) {
    for (i=1; i<=length(heading); i++) {
      if(length($i) > 0) { 
        print(heading[i] ": " $i)
      } 
    }
    print("")
  }
}'  Input_file
awk'开始{FS=“,”;}
{gsub(/\r/,“”)}
NR==1{
对于(i=1;i1{
如果($0~regex){
对于(i=1;i0){
打印(标题[i]:“$i)
} 
}
打印(“”)
}
}'输入文件

I您的数据文件有DOS样式的
\r\n
行尾。单词“committeed”实际上是
committeed\r
,因此光标被发送到冒号之前的行首并打印值。Glenn如果
长度(标题),我不能投票支持您的注释
不等于
NF
那么您就有问题了,因此
iI不希望循环在没有要连接的头的情况下产生格式化输出。因此,如果它是一个混乱的CSV文件,其中只提供了3个头,但数据有5列……但是awk的长度函数似乎能够理解上下文并给出正确的输出f或者数组长度。@JasperZanjani我修改了答案以反映评论中提到的问题。
$ ./csv.sh HMS ships.csv 
name: HMS Dreadnought
country: United Kingdom
displacement: 18120
length: 160.6
beam: 25

name: HMS Vanguard
country: United Kingdom
displacement: 45200
length: 248.2
beam: 32.9
awk 'BEGIN {FS=",";}
{gsub(/\r/,"")}
NR==1 { 
  for (i=1; i<=NF; i++) { 
    heading[i]=$i; 
  } 
}
NR>1 {
  if ($0 ~ regex) {
    for (i=1; i<=length(heading); i++) {
      if(length($i) > 0) { 
        print(heading[i] ": " $i)
      } 
    }
    print("")
  }
}'  Input_file