繁体   English   中英

如何根据模式重新编码文本文件中的行?

[英]How can i reoder lines in a text file based on a pattern?

我有一个包含 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' 

但是我不知道如何实现类似的处理多行的东西。

我怎样才能做到这一点?

通过将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

你能不能试试以下。

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

最简单的方法如下:

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 知道记录字段的概念。 文件被分割成记录,其中连续的记录被记录分隔符RS分割。 每条记录都拆分为字段,其中连续的字段由字段分隔符FS拆分。 默认情况下,记录分隔符RS设置为 <newline> 字符 ( \\n ),因此每条记录都是一行。 记录分隔符的定义如下:

RS的字符串值的第一个字符RS应输入记录分隔符; 默认为 <newline>。 如果RS包含多个字符,则结果未指定。 如果RS为空,则记录由由 <newline> 加上一个或多个空行组成的序列分隔,前导或尾随空行不应在输入的开头或结尾导致空记录,并且 <newline> 应无论FS的值是什么,始终是字段分隔符。

因此,使用您提供的文件格式,我们可以根据RS=""和字段分隔符 `FS="\\n" 定义记录。

每条记录看起来都简化为:

key1 string1      << field $1
key2 string2      << field $2
key3 string3      << field $3
key4 string4      << field $4
...
keyNF stringNF    << field $NF

当 awk 读取一条记录时,我们首先通过将所有key-value对存储在数组a解析它。 之后,我们要求打印我们觉得有趣的值。 为此,我们需要定义输出字段分隔符OFS和输出记录分隔符ORS

在 Vim 中,您可以使用逆序排序对文件进行分段sort!

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM