テキストファイルの行をランダムにシャッフルして、新しいファイルを作成します。ファイルには数千行ある場合があります。
どのように私はそれを行うことができ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
確定的です。同じ入力で異なる時間に2回呼び出すと、同じ答えが返されます。shuf
一方、はランダムな出力を生成するため、同じ入力で異なる出力が得られる可能性が高くなります。
Perlワンライナーはマキシムのソリューションの単純なバージョンになります
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.2 GHz Intel Core i5とFusion Driveを搭載した2012年後半のiMacで取得されました。タイミングは、使用するOS、マシンの仕様、awk
使用する実装によって異なります(たとえば、awk
OSXで使用されるBSD バージョンは、通常、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.2awk
+ sort
+cut
3.003s
BSDでawk
; 2.388s
GNU awk
(4.1.1); (1.3.4)。1.811s
mawk
さらに比較するために、上記の関数としてパッケージ化されていないソリューション:
sort -R
(重複する入力行がある場合、本当のシャッフルではありません)
10.661s
-より多くのメモリを割り当てても違いはないようです24.229s
bash
ループ+ sort
32.593s
結論:
shuf
可能な場合はを使用してください。これがはるかに高速です。awk
+ sort
+ cut
最後の手段としてコンボを。どのawk
実装を使用するかが重要です(mawk
GNUより高速でawk
、BSD awk
が最も低速です)。sort -R
、bash
ループ、およびスカラ。PythonソリューションのWindowsバージョン(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
コマンドレットを介してネイティブにシャッフルできることに注意してください(パフォーマンスが問題になる可能性があります)。例えば:
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);
、元のソリューションを省略しても十分であり、ファイル名引数を渡すこともできるという柔軟性を保持しています。他に何も変更する必要はありません(引用符を除く)-に追加した新しいセクションを参照してください底。
私は「unsort」と呼ぶ小さなperlスクリプトを使用します。
#!/usr/bin/perl
use List::Util 'shuffle';
@list = <STDIN>;
print shuffle(@list);
「unsort0」と呼ばれるNULLで区切られたバージョンもあります。find-print0などで使用すると便利です。
PS: '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の間の10進数であり、重要なのは何らかの方法で並べ替えられることだけなので、並べ替えの必要はありません。-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のワンライナー:
python -c "import random, sys; lines = open(sys.argv[1]).readlines(); random.shuffle(lines); print ''.join(lines)," myFile
そして、ランダムな1行だけを印刷する場合:
python -c "import random, sys; print random.choice(open(sys.argv[1]).readlines())," myFile
しかし、pythonの欠点については、この投稿を参照してくださいrandom.shuffle()
。多くの(2080を超える)要素ではうまく機能しません。
/dev/urandom
。Pythonから使用するには: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
数値を理解できないシステムでも正しく機能することに注意してください。これは、辞書式順序(別名通常の文字列比較)でソートできます。
"$@"
、入力としてファイルを使用することもできます。乗算する理由はありませんrand()
ので、sort -n
小数点以下の端数をソートすることができます。ただし、awk
の出力形式を制御することをお勧めします。デフォルトの形式では%.6g
、指数表記でrand()
時々の数が出力されるためです。実際には、最大100万行をシャッフルすることで間違いなく十分ですが、パフォーマンスを犠牲にすることなく、より多くの行をサポートすることは簡単です。例えば。%.17f
sort
小数部を処理できるはずです(私が気付いたように、何千ものセパレータがあっても)。
Ruby FTW:
ls | ruby -e 'puts STDIN.readlines.shuffle'
puts ARGF.readlines.shuffle
と、stdin入力引数とファイル名引数の両方で機能させることができます。
ruby -e 'puts $<.sort_by{rand}'
— ARGFはすでに列挙可能であるため、ランダムな値で並べ替えることで行をシャッフルできます。
これは、ホームフォルダにrand.pyとして保存したpythonスクリプトです。
#!/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
ます。
Scalaがインストールされている場合、入力をシャッフルするためのワンライナーは次のとおりです。
ls -1 | scala -e 'for (l <- util.Random.shuffle(io.Source.stdin.getLines.toList)) println(l)'
この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