개행으로 구분된 문자열이 포함된 텍스트 파일이 있습니다. 내 문제는 각 줄을 다음과 같이 처리하는 것입니다. 공백을 구분 기호로 사용하여 토큰 순서를 섞습니다.
예를 들어:
입력하다:
A B C
산출:
C A B
물론 명령/스크립트를 반복적으로 실행하면 다른 순서가 제공되어야 합니다.
내 현재 솔루션(한 줄의 텍스트):
$ cat <file> | tr " " "\n" | shuf | tr "\n" " "
여러 줄의 텍스트 파일을 처리하기 위한 좋은(더 나은) 명령줄 조합이 있습니까?
답변1
POSIXly에서는 다음과 같이 이 작업을 상대적으로 효율적으로 수행할 수 있습니다(확실히 awk
모든 입력 줄에 대해 하나 이상의 GNU 유틸리티를 실행하는 것보다 더 효율적).shuf
awk '
BEGIN {srand()}
{
for (i = 1; i <= NF; i++) {
r = int(rand() * NF) + 1
x = $r; $r = $i; $i = x
}
print
}' < your-file
(대부분의 awk
구현에서 동일한 명령을 동일한 초 내에 두 번 실행하면 동일한 결과가 나올 수 있습니다. 사용되는 기본 무작위 시드는 srand()
일반적으로 초 단위의 현재 에포크 시간을 기반으로 하기 때문입니다.)
답변2
원래 명령을 다음과 같이 단순화할 수 있습니다.
shuf -e A B C | tr "\n" " " && echo ""
또는
shuffled=( $(shuf -e A B C) ) ; echo ${shuffled[*]}
내 생각엔 이것이 기본 테스트보다 덜 번거롭고 더 빠르다고 생각합니다.
~/test
포함된 파일이 있는 경우
A B C
D E F
다음을 사용하여 각 라인을 스크램블하고 에코할 수 있습니다.
while IFS= read -r line; do shuffled=( $(shuf -e $line) ) ; echo ${shuffled[*]} ; done < ~/test
또는 스크립트 형식으로:
#!/bin/bash
while IFS= read -r line
do shuffled=( $(shuf -e $line) )
echo ${shuffled[*]}
done < ~/test
스크립트에 인수를 전달할 ~/test
위치 를 바꿀 수 있습니다 .$1
결과:
B C A
G E F
작동 원리:
shuf -e
공백과 줄 바꿈으로 분할됩니다. 하지만 이는 ABC를 세 개의 인수로 처리하기 때문입니다.
따라서
shuf -e A B C
AB와 C의 순서는 깨지게 되지만 shuf -e "A B C"
AB와 C의 순서는 깨지지 않게 됩니다.
이를 사용하여 각 줄을 배열로 읽은 다음 를 사용하여 다시 인쇄할 수 있습니다 echo
.
while IFS= read -r line;
$line
각 행은 이 루프에 전달될 때 읽혀집니다 <
.
do shuffled=( $(shuf -e $line) )
$shuffled
리터럴 확장을 통해 shuf -e $line
변수의 각 행에서 배열이 생성됩니다 shuf -e A B C
.
echo ${shuffled[*]}
기본적으로 각 요소 사이에 공백을 넣어 인쇄하는 배열을 에코합니다.
< ~/test
~/test
루프에 라인을 입력하십시오 .
답변3
주어진
$ cat file
A B C
D E F
G H I J
shuffle
그런 다음 Perl의 List::Util 모듈을 사용하십시오 .
$ perl -MList::Util=shuffle -alpe '$_ = join " ", shuffle @F' file
C B A
E D F
I J G H
bash를 사용 read -a
하고 shuf
(그러나 한 줄에 3개의 유틸리티를 실행하고 그 중 2개는 내장되어 있지 않으므로 매우 비효율적입니다):
$ while read -ra arr; do shuf -e -- "${arr[@]}" | paste -sd ' ' -; done < file
A C B
F E D
J I G H
답변4
매개변수를 한 줄로 전달하려면:
shuf -e one two three four
그게 당신이 필요한 전부입니다.
shuf -e $(cat <file>) | tr "\n" " "
예제에 표시된 것처럼 한 줄만 있는 파일의 경우.
여러 줄의 경우:
while read line; do shuf -e $line | tr "\n" " " && echo \n; done < <file>