텍스트 파일의 줄을 무작위로 섞고 새 파일을 만들고 싶습니다. 파일에는 수천 줄이있을 수 있습니다.
어떻게 함께 그렇게 할 수 cat
, awk
, cut
, 등?
텍스트 파일의 줄을 무작위로 섞고 새 파일을 만들고 싶습니다. 파일에는 수천 줄이있을 수 있습니다.
어떻게 함께 그렇게 할 수 cat
, awk
, cut
, 등?
답변:
사용할 수 있습니다 shuf
. 적어도 일부 시스템에서는 (POSIX에없는 것으로 보입니다).
jleedev가 지적했듯이 : sort -R
옵션 일 수도 있습니다. 일부 시스템에서는 최소한; 글쎄, 당신은 사진을 얻을. 실제로 섞는 것이 아니라 해시 값에 따라 항목을 정렬 하는 것으로 나타났습니다sort -R
.
[편집자 주 : 중복 줄 / 정렬 키가 항상 서로 옆에 있다는 점을 제외하고는 sort -R
거의 섞 습니다 . 다시 말해, 고유 한 입력 라인 / 키만 있으면 진정한 셔플입니다. 출력 순서가 해시 값에 의해 결정되는 것은 사실이지만 , 임의성은 임의 해시 함수 를 선택하여 비롯됩니다 . 설명서를 참조하십시오 .]
shuf
그리고이 sort -R
때문에, 약간 다른 sort -R
무작위 순서 요소가있어서 해시 그들 중, sort -R
함께있는 동안 반복 요소를 넣어 shuf
랜덤 셔플 모든 요소.
brew install coreutils
다음 사용 gshuf ...
(:
sort -R
와 shuf
완전히 다른로 볼 수 있습니다. sort -R
결정적입니다. 동일한 입력에서 다른 시간에 두 번 호출하면 동일한 답변을 얻을 수 있습니다. shuf
반면에 무작위 출력을 생성하므로 동일한 입력에서 다른 출력을 제공 할 가능성이 높습니다.
Perl one-liner는 Maxim 솔루션의 간단한 버전입니다.
perl -MList::Util=shuffle -e 'print shuffle(<STDIN>);' < myfile
\n
. 네, 그 \n
존재해야합니다 - 그것은 일반적 이다 - 그렇지 않으면 당신은 당신이 설명하는 것을 얻을 수 있습니다.
<STDIN>
과 <>
솔루션의 입력으로 작동하므로, 파일 이 너무.
이 답변은 다음과 같은 방식으로 기존의 많은 훌륭한 답변을 보완합니다.
기존 답변은 유연한 쉘 함수 로 패키지됩니다 .
stdin
입력뿐만 아니라 파일 이름 인수도 사용합니다.SIGPIPE
141
노이즈를 제거하는 것과는 달리 일반적인 방법 으로 처리하기 위해 추가 단계를 수행합니다 (종료 코드로 조용한 종료 ). 이것은 배관을 할 때와 같이 일찍 닫힌 파이프로 기능 출력을 배관 할 때 중요합니다 head
.성능을 비교 한다.
awk
, sort
그리고cut
는에서 적응 OP 자신의 대답 :shuf() { awk 'BEGIN {srand(); OFMT="%.17f"} {print rand(), $0}' "$@" |
sort -k1,1n | cut -d ' ' -f2-; }
shuf() { perl -MList::Util=shuffle -e 'print shuffle(<>);' "$@"; }
shuf() { python -c '
import sys, random, fileinput; from signal import signal, SIGPIPE, SIG_DFL;
signal(SIGPIPE, SIG_DFL); lines=[line for line in fileinput.input()];
random.shuffle(lines); sys.stdout.write("".join(lines))
' "$@"; }
이 기능 의 Windows 버전은 하단 섹션을 참조하십시오 .
shuf() { ruby -e 'Signal.trap("SIGPIPE", "SYSTEM_DEFAULT");
puts ARGF.readlines.shuffle' "$@"; }
성능 비교 :
참고 :이 수치는 OSX 10.10.3을 실행하는 3.2GHz Intel Core i5 및 Fusion Drive가 장착 된 2012 년 말 iMac에서 구했습니다. 타이밍은 사용 된 OS, 기계 사양, awk
사용 된 구현 (예 : awk
OSX에서 사용되는 BSD 버전이 일반적으로 GNU보다 느리고 awk
특히 mawk
)에 따라 달라질 수 있지만 , 이는 상대적 성능에 대한 일반적인 의미를 제공해야합니다 .
입력 파일은로 만든 1 백만 줄 파일 입니다 seq -f 'line %.0f' 1000000
.
시간은 오름차순으로 나열됩니다 (가장 빠른 것부터).
shuf
0.090s
0.289s
0.589s
1.342s
파이썬 2.7.6; 2.407s
파이썬 3.4.2에서 (!)awk
+ sort
+cut
3.003s
BSD와 함께 awk
; 2.388s
GNU awk
(4.1.1) 와 함께 ; 1.811s
와 mawk
(1.3.4);추가 비교를 위해 위의 기능으로 패키지화되지 않은 솔루션 :
sort -R
(중복 입력 라인이있는 경우 진정한 셔플이 아닙니다)
10.661s
-더 많은 메모리를 할당해도 차이가없는 것 같습니다24.229s
bash
루프 + sort
32.593s
결론 :
shuf
, 당신이 할 수있는 경우 - 그것은 지금까지 가장 빠른입니다.awk
+ sort
+ cut
콤보를 최후의 수단으로 사용하십시오 . 어떤 awk
구현을 사용 하는지 중요합니다 ( mawk
GNU보다 빠르며 awk
BSD awk
가 가장 느립니다).sort -R
, bash
루프 및 스칼라.Windows 버전의 Python 솔루션 (Python 코드는 Windows에서 지원되지 않는 신호 관련 명령문의 인용 및 변형을 제외하고는 동일합니다) :
$OutputEncoding
경우 파이프 라인을 통해 비 ASCII 문자를 보내려면 조정 해야 함) :# Call as `shuf someFile.txt` or `Get-Content someFile.txt | shuf`
function shuf {
$Input | python -c @'
import sys, random, fileinput;
lines=[line for line in fileinput.input()];
random.shuffle(lines); sys.stdout.write(''.join(lines))
'@ $args
}
PowerShell은 기본적으로 Get-Random
cmdlet을 통해 섞을 수 있습니다 (성능에 문제가있을 수 있음). 예 :
Get-Content someFile.txt | Get-Random -Count ([int]::MaxValue)
cmd.exe
(배치 파일) :파일에 저장하십시오 ( shuf.cmd
예 :
@echo off
python -c "import sys, random, fileinput; lines=[line for line in fileinput.input()]; random.shuffle(lines); sys.stdout.write(''.join(lines))" %*
python -c "import sys, random; lines = [x for x in sys.stdin.read().splitlines()] ; random.shuffle(lines); print(\"\n\".join([line for line in lines]));"
from signal import signal, SIGPIPE, SIG_DFL; signal(SIGPIPE, SIG_DFL);
원래 솔루션을 생략 하는 것으로 충분하며 파일 이름 인수 를 전달할 수있는 유연성을 유지합니다 -다른 것을 변경할 필요가 없습니다 (인용 제외)-에 추가 한 새로운 섹션을 참조하십시오 바닥.
나는 "정렬하지 않은"작은 펄 스크립트를 사용한다 :
#!/usr/bin/perl
use List::Util 'shuffle';
@list = <STDIN>;
print shuffle(@list);
또한 "unsort0"이라는 NULL로 구분 된 버전이 있는데 find -print0 등에 사용하기 편리합니다.
추신 : 'shuf'도 투표했습니다. 요즘 coreutils에 있는지 전혀 몰랐습니다 ... 시스템에 'shuf'가 없으면 위의 내용이 여전히 유용 할 수 있습니다.
<STDIN>
하는 것이 좋습니다 . <>
다음은 코더에서는 쉽지만 각 줄에 난수를 추가하고 정렬 한 다음 각 줄에서 난수를 제거하는 CPU에서는 어려운 첫 번째 시도입니다. 실제로 선은 무작위로 정렬됩니다.
cat myfile | awk 'BEGIN{srand();}{print rand()"\t"$0}' | sort -k1 -n | cut -f2- > myfile.shuffled
head myfile | awk ...
.로 디버깅합니다 . 그런 다음 그냥 고양이로 바꿉니다. 그것이 그곳에 남아있는 이유입니다.
-k1 -n
awk의 출력은 rand()
0과 1 사이의 십진수 이기 때문에 정렬 할 필요가 없으며 중요한 것은 어떻게 든 순서가 재정렬되기 때문입니다. -k1
rand ()의 출력은 비교를 단락시킬만큼 고유해야하지만 나머지 줄을 무시하여 속도를 높이는 데 도움이 될 수 있습니다.
cat filename |
(또는 < filename |
) 를 유지하는 것이 좋습니다 .
여기 awk 스크립트가 있습니다
awk 'BEGIN{srand() }
{ lines[++d]=$0 }
END{
while (1){
if (e==d) {break}
RANDOM = int(1 + rand() * d)
if ( RANDOM in lines ){
print lines[RANDOM]
delete lines[RANDOM]
++e
}
}
}' file
산출
$ cat file
1
2
3
4
5
6
7
8
9
10
$ ./shell.sh
7
5
10
9
6
8
2
1
3
4
파이썬을위한 하나의 라이너 :
python -c "import random, sys; lines = open(sys.argv[1]).readlines(); random.shuffle(lines); print ''.join(lines)," myFile
그리고 하나의 임의의 줄만 인쇄하려면 다음을 수행하십시오.
python -c "import random, sys; print random.choice(open(sys.argv[1]).readlines())," myFile
그러나 파이썬의 단점에 대해서는 이 게시물 을 참조하십시오 random.shuffle()
. 많은 (2080 개 이상의) 요소에서는 잘 작동하지 않습니다.
/dev/urandom
. 파이썬에서 활용하려면 : random.SystemRandom().shuffle(L)
.
.readLines()
있는 줄 을 반환 하기 때문 입니다.
간단한 awk 기반 함수가 작업을 수행합니다.
shuffle() {
awk 'BEGIN{srand();} {printf "%06d %s\n", rand()*1000000, $0;}' | sort -n | cut -c8-
}
용법:
any_command | shuffle
이것은 거의 모든 UNIX에서 작동합니다. Linux, Solaris 및 HP-UX에서 테스트되었습니다.
최신 정보:
선행 제로 ( %06d
) 및 rand()
곱셈은 sort
숫자를 이해하지 못하는 시스템에서도 올바르게 작동 합니다. 사전 식 순서 (일명 일반 문자열 비교)를 통해 정렬 할 수 있습니다.
"$@"
작업도 수행됩니다 . 곱셈에 대한 이유가 없습니다 때문에, 소수의 분수를 정렬 할 수 있습니다. 그것은, 그러나, 컨트롤에 대한 좋은 아이디어입니다 때문에 기본 형식으로의 출력 형식 , 출력됩니다에서 가끔 수를 지수 표기법. 실제로는 최대 1 백만 라인을 섞는 것으로 충분하지만 성능 저하없이 많은 라인을 쉽게 지원할 수 있습니다. 예 . rand()
sort -n
awk
%.6g
rand()
%.17f
sort
소수 분수를 처리 할 수 있습니다 (방금 알았 듯이 수천 개의 구분 기호를 사용하더라도).
간단하고 직관적 인 방법은 사용하는 것 shuf
입니다.
예:
다음 words.txt
과 같이 가정하십시오 .
the
an
linux
ubuntu
life
good
breeze
라인을 섞으려면 다음을 수행하십시오.
$ shuf words.txt
셔플 된 라인을 표준 출력으로 던집니다 . 따라서 다음 과 같은 출력 파일 로 파이프 해야합니다 .
$ shuf words.txt > shuffled_words.txt
이러한 셔플 실행 중 하나 가 발생할 수 있습니다.
breeze
the
linux
an
ubuntu
good
life
이것은 내 홈 폴더에 rand.py로 저장 한 파이썬 스크립트입니다.
#!/bin/python
import sys
import random
if __name__ == '__main__':
with open(sys.argv[1], 'r') as f:
flist = f.readlines()
random.shuffle(flist)
for line in flist:
print line.strip()
맥 OSX에 sort -R
와 shuf
당신이 같은 bash_profile이 별칭을 할 수 있도록 사용할 수 없습니다 :
alias shuf='python rand.py'
나처럼 당신이 여기 shuf
macOS 에 대한 대안을 찾기 위해 온 다면를 사용하십시오 randomize-lines
.
기능이 유사한 명령 randomize-lines
이있는 (homebrew) 패키지를 설치하십시오 .rl
shuf
brew install randomize-lines
Usage: rl [OPTION]... [FILE]...
Randomize the lines of a file (or stdin).
-c, --count=N select N lines from the file
-r, --reselect lines may be selected multiple times
-o, --output=FILE
send output to file
-d, --delimiter=DELIM
specify line delimiter (one character)
-0, --null set line delimiter to null character
(useful with find -print0)
-n, --line-number
print line number with output lines
-q, --quiet, --silent
do not output any errors or warnings
-h, --help display this help and exit
-V, --version output version information and exit
brew install coreutils
하면 shuf
바이너리가로 제공 됩니다 gshuf
.
이 bash 함수는 최소한의 의존성을 갖습니다 (정렬과 bash 만).
shuf() {
while read -r x;do
echo $RANDOM$'\x1f'$x
done | sort |
while IFS=$'\x1f' read -r x y;do
echo $y
done
}
awk
지원 솔루션 과 유사한 멋진 bash 솔루션 이지만 더 큰 입력에서는 성능에 문제가 있습니다. 단일 $RANDOM
값을 사용 하면 최대 32,768 개의 입력 라인 만 올바르게 섞습니다. 예를 들어 내 컴퓨터에서 32,768 개의 짧은 입력 줄에서 스크립트를 실행하는 데 약 1 초가 shuf
걸리며 실행 시간보다 약 150 배 , 약 10-15 배 OP의 자체 awk
지원 솔루션이 필요한 한 당신 sort
이 존재 하는 것에 의존 할 수 있다면 , awk
거기도 있어야합니다.
Windows 에서이 배치 파일 을 사용하여 data.txt를 섞을 수 있습니다. 배치 코드 사용법은 다음과 같습니다.
C:\> type list.txt | shuffle.bat > maclist_temp.txt
이 명령을 실행하면 maclist_temp.txt에 무작위 행 목록이 포함됩니다.
도움이 되었기를 바랍니다.
아직 언급되지 않은 내용 :
unsort
UTIL. 구문 (일부 재생 목록 중심) :
unsort [-hvrpncmMsz0l] [--help] [--version] [--random] [--heuristic]
[--identity] [--filenames[=profile]] [--separator sep] [--concatenate]
[--merge] [--merge-random] [--seed integer] [--zero-terminated] [--null]
[--linefeed] [file ...]
msort
한 줄씩 섞을 수 있지만 일반적으로 과잉입니다.
seq 10 | msort -jq -b -l -n 1 -c r