318

テキストファイルの行をランダムにシャッフルして、新しいファイルを作成したいと思います。ファイルには数千行が含まれる場合があります。

、、、などcatでそれを行うにはどうすればよいですか?awkcut

4

19 に答える 19

398

使用できますshuf。少なくとも一部のシステムでは (POSIX にはないようです)。

jleedevが指摘したように:sort -Rもオプションかもしれません。少なくとも一部のシステムでは。さて、あなたは絵を手に入れます。実際にはシャッフルするのではなく、ハッシュ値に従ってアイテムをソートすることが指摘されています。sort -R

[編集者注:重複する行/ソート キーが常に隣同士になることを除いて、sort -R ほとんどシャッフルします。つまり、一意の入力行/キーがある場合にのみ、真のシャッフルになります。出力順序がハッシュ値によって決定されるのは事実ですが、ランダム性はランダム ハッシュ関数の選択から生じます-マニュアルを参照してください。]

于 2010-01-28T10:51:34.550 に答える
90

Perl ワンライナーはマキシムのソリューションの単純なバージョンになります

perl -MList::Util=shuffle -e 'print shuffle(<STDIN>);' < myfile
于 2011-06-28T18:28:16.240 に答える
68

この回答は、次の方法で多くの優れた既存の回答を補完します。

  • 既存の回答は、柔軟なシェル関数にパッケージ化されています。

    • 関数は入力だけでなく、代わりにファイル名の引数も取りますstdin
    • 関数は、通常の方法(終了コードによる静かな終了) で処理するために追加の手順を実行しますSIGPIPE141。これは、 にパイプする場合など、関数の出力を早期に閉じられるパイプにパイプする場合に重要headです。
  • 性能比較が行われます。


  • OP自身の答えから適応された、、、およびにawk基づくsortPOSIXcut準拠関数:
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
  • ルビー2.0.0
    • 0.289s
  • パール5.18.2
    • 0.589s
  • パイソン
    • 1.342sPython 2.7.6; 2.407s(!) Python 3.4.2 で
  • awk+ sort+cut
    • 3.003sBSDでawk; 2.388sGNU awk(4.1.1) を使用。1.811s( mawk1.3.4);

さらに比較するために、上記の関数としてパッケージ化されていないソリューション:

  • sort -R(入力行が重複している場合、真のシャッフルではありません)
    • 10.661s-より多くのメモリを割り当てても違いはないようです
  • スカラ
    • 24.229s
  • bashループ +sort
    • 32.593s

結論

  • shuf可能な場合は を使用してください。これが群を抜いて最速です。
  • Rubyが好調で、 Perlがそれに続きます。
  • Pythonは Ruby や Perl よりも著しく遅く、Python のバージョンを比較すると、2.7.6 は 3.4.1 よりかなり高速です。
  • 最後の手段として POSIX 準拠の ++ コンボをawksortcut使用してくださいどのawk実装を使用するかが重要です ( mawkGNU より高速でawk、BSDawkが最も遅い)。
  • sort -Rbashループ、および Scala には近づかないでください。

WindowsバージョンのPythonソリューション(Windows ではサポートされていない、引用符のバリエーションとシグナル関連ステートメントの削除を除いて、Python コードは同じです):

  • PowerShell の場合 (Windows PowerShell では$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))" %*
于 2015-05-08T21:41:50.743 に答える
27

私は「unsort」と呼ぶ小さなperlスクリプトを使用しています。

#!/usr/bin/perl
use List::Util 'shuffle';
@list = <STDIN>;
print shuffle(@list);

「unsort0」と呼ばれるNULLで区切られたバージョンもあります...find-print0などで使用すると便利です。

PS:「shuf」にも投票しました。最近coreutilsにあるとは思いもしませんでした...システムに「shuf」がない場合でも、上記は役立つ可能性があります。

于 2010-01-28T13:10:13.203 に答える
22

これは、コーダーでは簡単ですが、CPUでは難しい最初の試みです。これは、各行に乱数を付加し、それらを並べ替えてから、各行から乱数を取り除きます。実際には、行はランダムに並べ替えられます。

cat myfile | awk 'BEGIN{srand();}{print rand()"\t"$0}' | sort -k1 -n | cut -f2- > myfile.shuffled
于 2010-01-28T10:50:47.340 に答える
16

これが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
于 2010-01-28T11:29:35.253 に答える
9

単純な 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辞書順(通常の文字列比較)でソートできます。

于 2011-10-12T18:24:30.203 に答える
6

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
于 2013-07-22T05:30:18.510 に答える
5

まさにその仕事をするためのパッケージがあります:

sudo apt-get install randomize-lines

例:

数字の順序付きリストを作成し、1000.txt に保存します。

seq 1000 > 1000.txt

シャッフルするには、単に使用します

rl 1000.txt
于 2016-09-11T14:22:46.017 に答える
2

Scala がインストールされている場合は、入力をシャッフルするためのワンライナーを次に示します。

ls -1 | scala -e 'for (l <- util.Random.shuffle(io.Source.stdin.getLines.toList)) println(l)'
于 2014-06-20T12:37:43.047 に答える
1

この 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
}
于 2015-01-22T03:34:21.033 に答える