假设我有一个结构如下的文件
/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
。 - -o
output.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
,从而可以轻松更改使用不同路径分隔符的系统。即使文件名是数字,函数""
中附加的空字符串也会强制进行词汇比较 - 例如参见mycmp
awk 如何在字符串和数字之间转换
如果你愿意坚持使用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 $0
为print $NF,$0
插入“丢失”的分隔符,然后可能使用正则表达式sub()
而不是更简单的方法$1 = ""
来删除前导元素。
除了可能比纯gawk
解决方案更快/更节省内存之外,这还允许sort
直接添加其他选项,例如cmd = "sort -d -t " FS " -k1,1r"
。