テキストファイルの行をランダムにシャッフルして、新しいファイルを作成したいと思います。ファイルには数千行が含まれる場合があります。
、、、などcat
でそれを行うにはどうすればよいですか?awk
cut
テキストファイルの行をランダムにシャッフルして、新しいファイルを作成したいと思います。ファイルには数千行が含まれる場合があります。
、、、などcat
でそれを行うにはどうすればよいですか?awk
cut
使用できますshuf
。少なくとも一部のシステムでは (POSIX にはないようです)。
jleedevが指摘したように:sort -R
もオプションかもしれません。少なくとも一部のシステムでは。さて、あなたは絵を手に入れます。実際にはシャッフルするのではなく、ハッシュ値に従ってアイテムをソートすることが指摘されています。sort -R
[編集者注:重複する行/ソート キーが常に隣同士になることを除いて、sort -R
ほとんどシャッフルします。つまり、一意の入力行/キーがある場合にのみ、真のシャッフルになります。出力順序がハッシュ値によって決定されるのは事実ですが、ランダム性はランダム ハッシュ関数の選択から生じます-マニュアルを参照してください。]
Perl ワンライナーはマキシムのソリューションの単純なバージョンになります
perl -MList::Util=shuffle -e 'print shuffle(<STDIN>);' < myfile
この回答は、次の方法で多くの優れた既存の回答を補完します。
既存の回答は、柔軟なシェル関数にパッケージ化されています。
stdin
SIGPIPE
141
。これは、 にパイプする場合など、関数の出力を早期に閉じられるパイプにパイプする場合に重要head
です。性能比較が行われます。
awk
基づくsort
POSIXcut
準拠の関数: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.2 GHz Intel Core i5 および Fusion Drive を搭載した 2012 年後半の iMac で取得されました。タイミングは、使用する OS、マシンの仕様、awk
使用する実装によって異なりますが (たとえば、 OSXで使用されるBSDawk
バージョンは通常、GNU よりも遅く、awk
特に.mawk
入力ファイルは で作成された100 万行のファイルですseq -f 'line %.0f' 1000000
。
時間は昇順 (早い順) にリストされています。
shuf
0.090s
0.289s
0.589s
1.342s
Python 2.7.6; 2.407s
(!) Python 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
、BSDawk
が最も遅い)。sort -R
、bash
ループ、および Scala には近づかないでください。WindowsバージョンのPythonソリューション(Windows ではサポートされていない、引用符のバリエーションとシグナル関連ステートメントの削除を除いて、Python コードは同じです):
$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
コマンドレットを介してネイティブにシャッフルできることに注意してください (ただし、パフォーマンスに問題がある場合があります)。例えば:
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))" %*
私は「unsort」と呼ぶ小さなperlスクリプトを使用しています。
#!/usr/bin/perl
use List::Util 'shuffle';
@list = <STDIN>;
print shuffle(@list);
「unsort0」と呼ばれるNULLで区切られたバージョンもあります...find-print0などで使用すると便利です。
PS:「shuf」にも投票しました。最近coreutilsにあるとは思いもしませんでした...システムに「shuf」がない場合でも、上記は役立つ可能性があります。
これは、コーダーでは簡単ですが、CPUでは難しい最初の試みです。これは、各行に乱数を付加し、それらを並べ替えてから、各行から乱数を取り除きます。実際には、行はランダムに並べ替えられます。
cat myfile | awk 'BEGIN{srand();}{print rand()"\t"$0}' | sort -k1 -n | cut -f2- > myfile.shuffled
これが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
単純な 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
辞書順(通常の文字列比較)でソートできます。
scai's answerに基づく Python の 1 つのライナーですが、a) stdin を使用し、b) シードを使用して結果を再現可能にし、c) すべての行から 200 行のみを選択します。
$ cat file | python -c "import random, sys;
random.seed(100); print ''.join(random.sample(sys.stdin.readlines(), 200))," \
> 200lines.txt
まさにその仕事をするためのパッケージがあります:
sudo apt-get install randomize-lines
例:
数字の順序付きリストを作成し、1000.txt に保存します。
seq 1000 > 1000.txt
シャッフルするには、単に使用します
rl 1000.txt
Scala がインストールされている場合は、入力をシャッフルするためのワンライナーを次に示します。
ls -1 | scala -e 'for (l <- util.Random.shuffle(io.Source.stdin.getLines.toList)) println(l)'
この bash 関数には最小限の依存関係があります (sort と bash のみ):
shuf() {
while read -r x;do
echo $RANDOM$'\x1f'$x
done | sort |
while IFS=$'\x1f' read -r x y;do
echo $y
done
}