根據以字串開頭的欄位對檔案進行排序

根據以字串開頭的欄位對檔案進行排序

假設我有一個如此結構化的文件

/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 表示字典排序。例如,蘋果公司先於貝瑞公司。
  • -k2 表示排序所依據的列,在本例中為第二列。請注意,第一列是第一列之前的所有內容-。例如,/home/zz/BOOKS/Author。第二列位於第一列 和第二列 之間-,即Artemis
  • -ooutput.txt將排序後的輸出重定向到檔案而不是終端。

希望這可以幫助

答案2

雖然對於當前的例子來說這是多餘的,因為user68186的答案中提出的解決方案,你可以更一般地在 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>

這類似於 GNUsort的簡單 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"

相關內容