텍스트 블록을 구분하는 빈 줄이 있는 텍스트 파일이 있습니다. *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";