多行檔案隨機播放

多行檔案隨機播放

我有一個文字文件,其中有分隔文字區塊的空白行。我想使用 *NIX 命令列工具來打亂此文件,同時尊重區塊結構。換句話說,在輸出中我想看到區塊的順序改變了;區塊內的行及其順序保持不變。

輸入檔案範例:

line 1
line 2

line 10
line 20
line 30

line 100
line 200

輸出檔案(隨機播放後):

line 10
line 20
line 30

line 1
line 2

line 100
line 200

當然,重複運行應該給出不同的區塊順序。

文件的第一行始終非空。沒有雙空行。文件的最後一行始終為空。

我編寫了一個非常簡單的 Python 腳本,它讀取列表列表中的所有行,對其進行打亂並輸出。我很好奇是否可以使用標準的 *NIX 工具來做到這一點。

答案1

POSIXly,你可以這樣做:

<file awk '
  BEGIN{srand(); n=rand()}
  {print n, NR, $0}
  !NF {n=rand()}
  END {if (NF) print n, NR+1, ""}' |
  sort -nk1 -k2 |
  cut -d' ' -f3-

也就是說,在每行前面加上<a-random-number-that-changes-with-each-paragraph>行號,然後對第一個數字進行數字排序,然後對第二個數字進行排序,以保持段落中的行順序並刪除那些多餘的數字。

人們可能需要透過管道來sed '$d'刪除尾隨的空白行。

請注意,大多數awk實作 srand()都使用 unix 紀元時間來為偽隨機數產生器提供種子,因此如果在同一秒內運行兩次,您可能會得到相同的結果(a不幸的是,儘管我付出了努力,但歷史錯誤現在已刻在 POSIX 規範中)。

答案2

使用 GNU 工具,這會將段落分成以 NUL 分隔的群組,對它們進行打亂,然後刪除 NUL:

$ sed '1s/^/\n/; s/^$/\x00/' input | shuf -z | sed '1d; s/\x00//'
line 100
line 200

line 10
line 20
line 30

line 1
line 2

不使用 NUL 的替代方法

由於並非所有工具都支援 NUL 字符,因此這裡有一個替代方案。這會讀取段落,替換~換行符,然後隨機播放,然後~在顯示結果之前將其轉換回換行符:

$ awk '{gsub(/\n/, "~")} 1' RS= input | shuf | awk '{gsub(/~/, "\n")} 1' ORS="\n\n"
line 10
line 20
line 30

line 100
line 200

line 1
line 2

如果您的文字可能包含~,則使用文字不包含的另一個字元作為臨時行分隔符號。

答案3

使用perl:

perl -MList::Util -00 -e 'chomp(my @a=<>); print join("\n\n", List::Util::shuffle @a) . "\n";' < input

或作為腳本文件展開:

#!/usr/bin/perl
use List::Util 'shuffle';
local $/ = "";  ## paragraph mode
chomp(my @a = <>);
print join("\n\n", shuffle @a) . "\n";

相關內容