如何使用第二行作为索引,在bash中一次对两行进行排序?

时间:2017-08-22 19:49:21

标签: linux bash sorting sed

我想使用bash在我的enigma2 dreambox中对我的频道列表进行排序。该文件如下所示:

#SERVICE 4097:0:1:0:0:0:0:0:0:0:http%3A//server.com/movie/1/new.aviM
#DESCRIPTION new 5[EN]
#SERVICE 4097:0:1:0:0:0:0:0:0:0:http%3A//server.com/movie/11/all2.mkvM
#DESCRIPTION all  2 [EN]
#SERVICE 4097:0:1:0:0:0:0:0:0:0:http%3A//server.com/movie/movie3.mp4M
#DESCRIPTION movie 3 [EN]

正如您在文件中看到的,每个通道包含两行。我想在bash中每次排序两行。

结果应如下所示:

#SERVICE 4097:0:1:0:0:0:0:0:0:0:http%3A//server.com/movie/11/all2.mkvM
#DESCRIPTION all  2 [EN]
#SERVICE 4097:0:1:0:0:0:0:0:0:0:http%3A//server.com/movie/movie3.mp4M
#DESCRIPTION movie 3 [EN]
#SERVICE 4097:0:1:0:0:0:0:0:0:0:http%3A//server.com/movie/1/new.aviM
#DESCRIPTION new 5[EN]

第一个是all 2 [EN],其上方有SERVICE

其次是电影movie 3 [EN],其上方有SERVICE

第三部分是电影new 5[EN],其上方有SERVICE

我现在正在使用循环,这非常慢。我认为这可以使用bash

更快地完成

可能的解决方案可能是,例如:

  • 将每两行合并为一行。第二行必须是第一行并将上面的行附加到它。结果应如下所示:

    #DESCRIPTION new 5[EN]#SERVICE 4097:0:1:0:0:0:0:0:0:0:http%3A//server.com/movie/1/new.aviM
    #DESCRIPTION all  2 [EN]#SERVICE 4097:0:1:0:0:0:0:0:0:0:http%3A//server.com/movie/11/all2.mkvM
    #DESCRIPTION movie 3 [EN]#SERVICE 4097:0:1:0:0:0:0:0:0:0:http%3A//server.com/movie/movie3.mp4M
    
  • 排序

  • 再次创建两行。

6 个答案:

答案 0 :(得分:1)

awk sed

#!/usr/bin/env bash

awk '/^#SERV/ {s=$0} /^#DESC/ {print s "\t" $0}' |
  sort -t $'\t' -k 2,2 |
  sed 's/\t/\n/'

答案 1 :(得分:0)

在接下来的解决方案中,我将在连接的行之间使用\ r \ n。在一个简单的Unix文本文件中,你不会有那些愚蠢的Window事物,它可以被sedtr替换。 如何以相反的顺序连接两条线?使用rev

rev inputfile |
   awk '{printf("%s%s",$0,(NR%2==0) ? "\n" : "\r")}' |
   rev | sort | tr '\r' '\n' 

使用sort密钥时,可以避免反转文件。我用CTRL-V CRTL-M输入^ M.在文件名后我不相信你的来信M,也许你更喜欢#

之类的东西
awk '{printf("%s%s",$0,(NR%2==0) ? "\n" : "\r")}' file |
   sort -t'^M' -k2,1 | tr '\r' '\n'

答案 2 :(得分:0)

awk 解决方案:

awk '/#SERVICE/ && getline nl > 0{ print nl"|"$0 | "sort -k2,2 -k3,3" }' file 
| awk -F'|' '{ print $2 ORS $1}'

输出:

#SERVICE 4097:0:1:0:0:0:0:0:0:0:http%3A//server.com/movie/11/all2.mkvM
#DESCRIPTION all  2 [EN]
#SERVICE 4097:0:1:0:0:0:0:0:0:0:http%3A//server.com/movie/movie3.mp4M
#DESCRIPTION movie 3 [EN]
#SERVICE 4097:0:1:0:0:0:0:0:0:0:http%3A//server.com/movie/1/new.aviM
#DESCRIPTION new 5[EN]

其他 sed 方法:

sed '/#DESCRIPTION/N;{s/\n/|/}' <(tac file) | sort -k2,2 -k3,3 | sed -E 's/(.*)\|(.*)/\2\n\1/'

答案 3 :(得分:0)

使用sed:

$ sed -E 'N;s/(.*)\n(.*)/\2\t\1/' infile | sort | sed -E 's/(.*)\t(.*)/\2\n\1/'
#SERVICE 4097:0:1:0:0:0:0:0:0:0:http%3A//server.com/movie/11/all2.mkvM    
#DESCRIPTION all  2 [EN]
#SERVICE 4097:0:1:0:0:0:0:0:0:0:http%3A//server.com/movie/movie3.mp4M    
#DESCRIPTION movie 3 [EN]
#SERVICE 4097:0:1:0:0:0:0:0:0:0:http%3A//server.com/movie/1/new.aviM    
#DESCRIPTION new 5[EN]

第一个命令追加下一行(N),然后交换第一行和第二行,制表符分隔。然后将其传送到sort,第二个sed命令再次交换行,并用换行符替换选项卡。

这要求在处理之前不存在制表符。

答案 4 :(得分:0)

谢谢大家。有两种选择。

选项1

awk '/^#SERV/ {s=$0} /^#DESC/ {print s "\t" $0}' file.txt  | sort -t $'\t' -k 2,2 |sed 's/\t/\n/' 

选项2

 awk '/#SERVICE/ && getline nl > 0{ print nl"|"$0 | "sort -k2,2 -k3,3" }' /tmp/test.txt   | awk -F'|' '{ print $2 ORS $1}'

我现在要学习一些高级awk命令

答案 5 :(得分:0)

谢谢,我正在使用第一个AWK示例(选项2),并且运行良好。 这意味着文件(带有“成对”的行(#SERVICE和#DESCRIPTION))排序良好。

关于具有相同结构的文件,我还有另一个问题。

是否可以扩大排序范围,这样:

该文件按字母顺序排序(与现在一样),但也要确保该文件的顶部是所有高清通道(按字母顺序排序),然后是其余所有高清通道(非高清通道)。 HD频道的行尾确实有“ HD”,从“ #DESCRIPTION”开始。

所需的输出示例:

#SERVICE 4097:0:1:0:0:0:0:0:0:0:...etc
#DESCRIPTION Sky Action HD
#SERVICE 4097:0:1:0:0:0:0:0:0:0:...etc
#DESCRIPTION Sky Cinema HD
#SERVICE 4097:0:1:0:0:0:0:0:0:0:...etc
#DESCRIPTION Sky Family HD
#SERVICE 4097:0:1:0:0:0:0:0:0:0:...etc
#DESCRIPTION Sky Action
#SERVICE 4097:0:1:0:0:0:0:0:0:0:...etc
#DESCRIPTION Sky Cinema
#SERVICE 4097:0:1:0:0:0:0:0:0:0:...etc
#DESCRIPTION Sky Family