다중 라인 파일 무작위 재생

다중 라인 파일 무작위 재생

텍스트 블록을 구분하는 빈 줄이 있는 텍스트 파일이 있습니다. *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()유닉스 에포크 시간을 사용하여 의사 난수 생성기를 시드하므로 동일한 초 내에 두 번 실행하면 동일한 결과를 얻을 수 있습니다.불행하게도 나의 노력에도 불구하고 이제 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 -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";

관련 정보