Shell 如何根据模式重新排序文本文件中的行?

Shell 如何根据模式重新排序文本文件中的行?,shell,awk,sed,grep,Shell,Awk,Sed,Grep,我有一个文本文件,包含4行的批次,每个批次的第一行在正确的位置,但接下来的3行并不总是在正确的顺序 name cat label 4 total 5 value 4 name dog total 4 label 3 value 6 name cow value 6 total 1 label 4 name fish total 3 label 5 value 6 我希望每个4行批次采用以下格式: name cat value 4 total 5 label 4 因此,输出将是: nam

我有一个文本文件,包含4行的批次,每个批次的第一行在正确的位置,但接下来的3行并不总是在正确的顺序

name cat
label 4
total 5
value 4

name dog
total 4
label 3
value 6

name cow
value 6
total 1
label 4

name fish
total 3
label 5
value 6
我希望每个4行批次采用以下格式:

name cat
value 4
total 5
label 4
因此,输出将是:

name cat
value 4
total 5
label 4

name dog
value 6
total 4
label 3

name cow
value 6
total 1
label 4

name fish
value 6
total 3
label 5
该文件总共包含数千行,因此我想构建一个命令,该命令可以处理这3行的所有潜在订单,如果没有以正确的格式重新排列它们

我知道我可以使用awk搜索以特定字符串开头的行并重新排列它们:

awk '$1 == "value" { print $3, $4, $1, $2; next; } 1' 
然而,我不知道如何实现在多条生产线上进行类似处理的东西


我怎样才能做到这一点呢?

你能试试下面的吗

awk '
/^name/{
  if(name){
    print name ORS array["value"] ORS array["total"] ORS array["label"] ORS
    delete array
  }
  name=$0
  next
}
{
  array[$1]=$0
}
END{
  print name ORS array["value"] ORS array["total"] ORS array["label"]
}
'  Input_file


编辑:添加Kvantour先生建议的上述精制溶液

awk -v OFS="\n" '
(!NF) && ("name" in a){
  print a["name"],a["value"],a["total"],a["label"] ORS
  delete a
  next
}
{
  a[$1]=$0
}
END{
  print a["name"],a["value"],a["total"],a["label"]
}
'  Input_file

通过将
RS
设置为空字符串,每个由至少一个空行分隔的文本块被视为一条记录。从那里很容易捕获每个键值对并按所需顺序输出它们

BEGIN {RS=""}
{
    for (i=1; i<=NF; i+=2) a[$i] = $(i+1)
    print "name", a["name"] ORS \
          "value", a["value"] ORS \
          "total", a["total"] ORS \
          "label", a["label"] ORS
}


$ awk -f a.awk file
name cat
value 4
total 5
label 4

name dog
value 6
total 4
label 3

name cow
value 6
total 1
label 4

name fish
value 6
total 3
label 5
开始{RS=”“}
{

对于(i=1;i而言,最简单的方法如下:

awk 'BEGIN{RS=""; ORS="\n\n"; FS=OFS="\n"}
     { for(i=1;i<=NF;++i) { k=substr($i,1,index($i," ")-1); a[k]=$i } }
     { print a["name"],a["value"],a["total"],a["label"] }' file

当awk读取一条记录时,我们首先通过将所有
键值对存储在数组
a
中来解析它。然后,我们要求打印我们感兴趣的值。为此,我们需要在Vim中定义输出字段分隔符
OFS
和输出记录分隔符
OR
,您可以在usi节中对文件进行排序ng反向排序
排序!

for i in range(1,line("$"))
  /^name/+1,/^name/+3sort!
endfor
从shell发出的相同命令:

$ ex -s '+for i in range(1,line("$"))|/^name/+1,/^name/+3sort!|endfor' '+%p' '+q!' inputfile

嗨,克万托尔,如果我可以问你,这个解决方案怎么样?这看起来更简单,你的意见是什么?@RavinderSingh13我对它发表了评论。我相信你的解决方案确实更简单。我只是喜欢利用awk的自然特性。这是一个好的解决方案,我只会改变打印,而不是基于
/name/
,而是基于空的l类似于
($NF==0)和&(“name”在一个{print array[“name”]ORS array[“value”]ORS array[“total”]ORS array[“label”]ORS;delete array;next}
这使得它更简短,更可读,更通用(假设
name
不是第一个条目),在高尔夫中,它看起来像
awk-v of s=“\n”(!NF)&(“name”在a){print a[“name”]、a[“value”]、a[“total”]、a[“label”]or;删除a;next{a[$1]=$0}END{print a[“name”]、a[“value”]、a[“total”]、a[“label”]}文件
您可以删除
OFS
,只需使用
即可。print语句用
OFS
替换
$ ex -s '+for i in range(1,line("$"))|/^name/+1,/^name/+3sort!|endfor' '+%p' '+q!' inputfile