Shell 如何根据模式重新排序文本文件中的行?
我有一个文本文件,包含4行的批次,每个批次的第一行在正确的位置,但接下来的3行并不总是在正确的顺序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
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