根据以字符串开头的字段对文件进行排序

根据以字符串开头的字段对文件进行排序

假设我有一个结构如下的文件

/home/zz/AUTHORBOOKS/Author-Chomsky-Who-Rules-the-World.epub
/home/zz/AUTHORBOOKS/Author-Cioran-Il-nulla.epub
/home/zz/BOOKS/Author-Artemis-Mathematica-Examples.nb
/home/zz/Books/Author-Zigniwe-Hisory-Medicine.pdf
/home/z1/OLDBOOKS1/OLDBOOKS2/Author-Watanabe-Waterloo.pdf
/home/z2/OLDBOOKS1/OLDBOOKS2/Author-Barbero-Lepanto.epub.pdf

我希望文件按如下方式排序:

/home/zz/BOOKS/Author-Artemis-Mathematica-Examples.nb
/home/z2/OLDBOOKS1/OLDBOOKS2/Author-Barbero-Lepanto.epub.pdf
/home/zz/AUTHORBOOKS/Author-Chomsky-Who-Rules-the-World.epub
/home/zz/AUTHORBOOKS/Author-Cioran-Il-nulla.epub
/home/z1/OLDBOOKS1/OLDBOOKS2/Author-Watanabe-Waterloo.pdf
/home/zz/Books/Author-Zigniwe-History-Medicine.pdf

也就是说,按字母顺序,根据字符串Author-...

正如您所见,的位置Author-...并不是恒定的。

我怎样才能做到这一点?

答案1

尝试以下bash命令:

sort -t- -d -k2 -o output.txt input.txt

它有四个选项加上输入文件的名称input.txt。如果此文件不在当前目录中,则必须提供path/to/the/folder/input.txt。选项及其参数如下:

  • -t 标记字段分隔符。我们使用-作为分隔符,以便之前和之后的所有内容-都被视为单独的列。
  • -d 表示字典排序。例如,Apple 排在 Berry 前面。
  • -k2 表示要排序的列,在本例中为第二列。请注意,第一列是第一个 之前的所有内容-。例如/home/zz/BOOKS/Author。第二列位于第一列和第二列之间-,即Artemis
  • -ooutput.txt将排序后的输出重定向到文件而不是终端。

希望这可以帮助

答案2

虽然对于本例来说,这是过度的,因为用户68186的回答中提出了解决方案,你通常可以在 GNU awk 中做这样的事情:

gawk -F/ '
  function mycmp(i1,v1,i2,v2) {
    m = split(v1,a);
    n = split(v2,b);
    return a[m]"" > b[n]"" ? 1 : a[m]"" < b[n]"" ? -1 : 0
  }
  {
    lines[NR] = $0
  }
  END {
    PROCINFO["sorted_in"] = "mycmp";
    for(i in lines) print lines[i]
  }
' file

请注意,它根据最后一个之后的所有内容的词汇值进行排序/- 因此,如果格式Author-<author name>-<title>.<extension>

  • 固定字符串Author-(没有效果,因为它对所有行都具有相同的权重);然后
  • <author name>-; 然后
  • <title>.; 然后
  • <extension>

sort这与 GNU的简单 KEYDEF 的工作方式类似-t- -k2,即有效排序键从 开始<author name>并一直延续到行尾。

调用中省略了显式分隔符split,以便它们继承 的值FS,从而可以轻松更改使用不同路径分隔符的系统。即使文件名是数字,函数""中附加的空字符串也会强制进行词汇比较 - 例如参见mycmpawk 如何在字符串和数字之间转换


如果你愿意坚持使用sort命令,你可以利用 GNU awk 的与另一个进程的双向通信到:

  • /复制字符串开头最后一个以 - 分隔的字段
  • 将结果传递给sort命令
  • 读回排序后的结果,删除重复的前缀并打印

IE

gawk -F/ '
  BEGIN {OFS=FS; cmd = "sort -d"} 
  {print $NF $0 |& cmd} 
  END {
    close(cmd,"to"); 
    while(cmd |& getline){$1 = ""; print};
    close(cmd,"from")
  }
' file

这里有一点欺骗,因为绝对路径(以 开头的行/)暗示初始为空字段;为了处理相对路径,您需要更改print $NF $0print $NF,$0插入“丢失”的分隔符,然后可能使用正则表达式sub()而不是更简单的方法$1 = ""来删除前导元素。

除了可能比纯gawk解决方案更快/更节省内存之外,这还允许sort直接添加其他选项,例如cmd = "sort -d -t " FS " -k1,1r"

相关内容