乱数を含む1GBのテキストファイルを生成する最速の方法は何ですか?

乱数を含む1GBのテキストファイルを生成する最速の方法は何ですか?

Bashスクリプトを試しましたが、単純な1MBファイルを生成するのに時間がかかりすぎました。/dev/randomorを使用すると答えが出てくるようですが/dev/urandom、ここの他の記事はこれらのものを使ってファイルにさまざまなデータを追加する方法だけを示していますが、私は数字だけを追加したいと思います。

それでは、サイズが1 GBで、0から9までの数字のみを含む任意のファイルを作成するために使用できるコマンドはありますか?

編集:出力が次のようになります。

0 1 4 7 ..... 9
8 7 5 8 ..... 8
....
....
8 7 5 3 ..... 3

範囲は0〜9で、数字0、1、2、3、4、5、6、7、8、9のみを意味します。また、スペースで区切られ、1行に100行、最大n行数が必要です。このnは私が気にしない部分です。最終サイズを1GBに設定したいです。

編集:Ubuntu 16.04 LTSを使用しています。

答え1

これ:

 LC_ALL=C tr '\0-\377' \
             '[0*25][1*25][2*25][3*25][4*25][5*25][6*25][7*25][8*25][9*25][x*]' \
    < /dev/urandom |
    tr -d x |
    fold -w 1 |
    paste -sd "$(printf '%99s\\n')" - |
    head -c1G

headサポートされている実装を想定-c)私のシステムではかなり速いようです。

trフルバイト範囲(0から255、8進数で0から0377)を変換します。最初の25バイトは0、次の25バイトは1です。それから25 9で、残りの部分(250から255)は「x」ですtr -d x/dev/urandomします。

これはバイトの97%に対して1桁の数字を生成します/dev/urandomfold -w 11行に1桁ずつ作成します。paste -s呼び出しは99個の空白文字と改行文字で構成される区切り文字のリストを使用して行われるため、各行にはスペースで区切られた100個の数字があります。

head -c1Gそのうちの最初のGiB(2 30)を取得します。最後の行は切り捨てられ、制限はありません。 2 30 -1 に切り捨てられ、行方不明の改行を手動で追加したり、200 バイト行の 5,000 万に相当する 10 9バイトのローザを作成したりできます(head -n 50000000これも標準/移植可能なコマンドです)。

zshクアッドコアシステムから得られるこれらのタイミングは、CPU時間が消費される場所を示す。

LC_ALL=C tr '\0-\377'  < /dev/urandom  0.61s user 31.28s system 99% cpu 31.904 total
tr -d x  1.00s user 0.27s system 3% cpu 31.903 total
fold -w 1  14.93s user 0.48s system 48% cpu 31.902 total
paste -sd "$(printf '%99s\\n')" -  7.23s user 0.08s system 22% cpu 31.899 total
head -c1G > /dev/null  0.49s user 1.21s system 5% cpu 31.898 total

最初trはボトルネックです。ほとんどの時間はカーネルで消費されます(乱数生成のため)。時間はバイトを取得できる速度とほぼ一致します/dev/uramdom(約19MiB / s、ここでは32MiB / sで/ dev / urandomの0.97バイトごとに2バイトを生成します)。fold各バイトの後に改行を挿入するだけでも無理なCPU時間(15秒)がかかるようですが、私の場合は別のCPUで動作したため、全体の時間には影響しません(該当-bオプションを追加して作成したものです。効率的でdd cbs=1 conv=unblockより良い選択のようです)。

サブシェルでhead -c1Gファイルサイズの制限を設定することで(他のほとんどのシェル(含む)を使用またはlimit filesize 1024m使用zsh)オーバーライドulimit -f "$((1024*1024))"し、数秒を節約できます。zsh

各バイトに対して2桁を抽出すると状況が改善される可能性がありますが、他のアプローチを取る必要があります。上記のコードは、tr256バイトの配列ですべてのバイトを見つけるだけでよいため、非常に効率的です。一度に2バイトに対してこれを行うことはできず、よりhexdump -e '1/1 "%02u"'複雑なアルゴリズムを使用して同様のアプローチを使用してバイトのテキスト表現を計算することは、乱数生成自体よりもコストがかかります。しかし、私の場合のように、利用可能なCPUコアがあれば、まだ数秒を節約できます。

そして:

< /dev/urandom LC_ALL=C tr '\0-\377' '\0-\143\0-\143[x*]' |
  tr -d x |
  hexdump -n250000000 -ve '500/1 "%02u" "\n"' |
  fold -w1 |
  paste -sd "$(printf '%99s\\n')" - > /dev/null

私は次のような結果を得ます(ただし、1,073,741,824ではなく1,000,000,000バイトであることに注意してください)。

LC_ALL=C tr '\0-\377' '\0-\143\0-\143[x*]' < /dev/urandom  0.32s user 18.83s system 70% cpu 27.001 total
tr -d x  2.17s user 0.09s system 8% cpu 27.000 total
hexdump -n250000000 -ve '500/1 "%02u" "\n"'  26.79s user 0.17s system 99% cpu 27.000 total
fold -w1  14.42s user 0.67s system 55% cpu 27.000 total
paste -sd "$(printf '%99s\\n')" - > /dev/null  8.00s user 0.23s system 30% cpu 26.998 total

全体的にCPU時間は多くなりますが、4つのCPUコアに分散しているため、壁時計の時間が少なくなります。これでボトルネックが発生しますhexdump

dd代わりに、行ベースを使用すると、fold実際に実行する必要がある作業量を減らし、hexdumpCPU間の作業バランスを向上させることができます。

< /dev/urandom LC_ALL=C tr '\0-\377' '\0-\143\0-\143[x*]' |
  tr -d x |
  hexdump -ve '"%02u"' |
  dd bs=50000 count=10000 iflag=fullblock status=none cbs=1 conv=unblock |
  paste -sd "$(printf '%99s\\n')" -

(ここではGNUddiflag=fullblockGNUを仮定status=none)、以下を提供します:

LC_ALL=C tr '\0-\377' '\0-\143\0-\143[x*]' < /dev/urandom  0.32s user 15.58s system 99% cpu 15.915 total
tr -d x  1.62s user 0.16s system 11% cpu 15.914 total
hexdump -ve '"%02u"'  10.90s user 0.32s system 70% cpu 15.911 total
dd bs=50000 count=10000 iflag=fullblock status=none cbs=1 conv=unblock  5.44s user 0.19s system 35% cpu 15.909 total
paste -sd "$(printf '%99s\\n')" - > /dev/null  5.50s user 0.30s system 36% cpu 15.905 total

乱数生成のボトルネックに戻ります。

@OleTangeが指摘したように、そのユーティリティがあれば、opensslそれを使用してより高速な(特にAES命令を持つプロセッサで)疑似ランダムバイトジェネレータを取得できます。

</dev/zero openssl enc -aes-128-ctr -nosalt -pass file:/dev/urandom

私のシステムから1秒あたりに噴出されるバイト数はです/dev/urandom。 (比較することはできません。)暗号化方式で安全なランダムソースこれがあなたのユースケースに適用される場合)。

</dev/zero openssl enc -aes-128-ctr -nosalt -pass file:/dev/urandom 2> /dev/null | 
  LC_ALL=C tr '\0-\377' '\0-\143\0-\143[x*]' |
  tr -d x |
  hexdump -ve '"%02u"' |
  dd bs=50000 count=10000 iflag=fullblock status=none cbs=1 conv=unblock |
  paste -sd "$(printf '%99s\\n')" -

今与えられた:

openssl enc -aes-128-ctr -nosalt -pass file:/dev/urandom < /dev/zero 2>   1.13s user 0.16s system 12% cpu 10.174 total
LC_ALL=C tr '\0-\377' '\0-\143\0-\143[x*]'  0.56s user 0.20s system 7% cpu 10.173 total
tr -d x  2.50s user 0.10s system 25% cpu 10.172 total
hexdump -ve '"%02u"'  9.96s user 0.19s system 99% cpu 10.172 total
dd bs=50000 count=10000 iflag=fullblock status=none cbs=1 conv=unblock  4.38s user 0.20s system 45% cpu 10.171 total
paste -sd "$(printf '%99s\\n')" - > /dev/null

hexdumpボトルネックに戻ります。

まだ空きCPUがあるため、そのうち3つを並列に実行できますhexdump

</dev/zero openssl enc -aes-128-ctr -nosalt -pass file:/dev/urandom 2> /dev/null | 
  LC_ALL=C tr '\0-\377' '\0-\143\0-\143[x*]' |
  tr -d x |
  (hexdump -ve '"%02u"' <&3 & hexdump -ve '"%02u"' <&3 & hexdump -ve '"%02u"') 3<&0 |
  dd bs=50000 count=10000 iflag=fullblock status=none cbs=1 conv=unblock |
  paste -sd "$(printf '%99s\\n')" -

(これはバックグラウンドで実行されたときに/ dev / nullのコマンドを閉じるstdinを<&3除くすべてのシェルに必要です。)zsh

これで6.2秒に短縮され、CPUがほぼ完全に活用されます。

答え2

これは質問のタイトルのために部分的に舌を突き合わせる答えです。

あなたが見つけるとき「最も速い方法は…」、答えはほとんど常に専門的なツールです。この「回答」は、実験できるツールの1つを示しています。

一度だけ実行したり、ほとんど実行しない作業のための専門ツールを見つけるべきではないので、真剣な答えではありません。実際に仕事をするよりもツールを見つけて学ぶのにもっと時間を費やすことになります。bashなどのシェルやユーティリティはawk最も高速ではありませんが、通常は次のように書くことができます。一つの線タスクを実行するには数秒しかかかりません。perl学習曲線は急ですが、このようなより良いスクリプト言語を使用することも可能であり、perl悪いPerlプロジェクトのために傷ついたので、そのような目的にお勧めします。python一方、遅いI / O速度にはわずかな欠点がありますが、これはギガバイトのデータをフィルタリングまたは生成する場合にのみ問題になります。

それにもかかわらず、次のC89サンプルプログラム(高精度クロックで利用可能な場合にのみPOSIX.1を使用)は、約100 MB / sの生成速度を達成する必要があります(Intel i5-4200Uプロセッサを搭載したノートブックのLinux)。テストで出力をパイプします。 )/dev/null、かなり良い疑似乱数ジェネレータを使用してください。 (出力は、MatrixRankテストを除くすべてのBigCrunchテストに合格する必要があります。XORシフト64 *数値偏向を避けるための除去方法。 )

10進数c:

#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <locale.h>
#include <ctype.h>
#include <stdio.h>
#include <errno.h>
#include <time.h>

/* This program is licensed under the CC0 license,
       https://creativecommons.org/publicdomain/zero/1.0/
   In other words, this is dedicated to the public domain.
   There are no warranties either, so if something breaks,
   you only have yourself to blame.
*/

#if _POSIX_C_SOURCE-199309 >= 0
static uint64_t time_seed(void)
{
    struct timespec  ts;

    if (clock_gettime(CLOCK_REALTIME, &ts))
        return (uint64_t)time(NULL);

    return (uint64_t)ts.tv_sec
         ^ (((uint64_t)ts.tv_nsec) << 32);
}
#else
static uint64_t time_seed(void)
{
    return (uint64_t)time(NULL);
}
#endif

/* Preferred output I/O block size.
 * Currently, about 128k blocks yield
 * maximum I/O throughput on most devices.
 * Note that this is a heuristic value,
 * and may be increased in the future.
*/
#ifndef  IO_BLOCK_SIZE
#define  IO_BLOCK_SIZE  262144
#endif

/* This is the Xorshift* pseudo-random number generator.
 * See https://en.wikipedia.org/wiki/Xorshift#xorshift.2A
 * for details. This is an incredibly fast generator that
 * passes all but the MatrixRank test of the BigCrush
 * randomness test suite, with a period of 2^64-1.
 * Note that neither xorshift_state, nor the result of
 * this function, will ever be zero.
*/
static uint64_t xorshift_state;

static uint64_t xorshift_u64(void)
{
    xorshift_state ^= xorshift_state >> 12;
    xorshift_state ^= xorshift_state << 25;
    xorshift_state ^= xorshift_state >> 27;
    return xorshift_state * UINT64_C(2685821657736338717);
}

/* This function returns a number between (inclusive)
 * 0 and 999,999,999,999,999,999 using xorshift_u64()
 * above, using the exclusion method. Thus, there is
 * no bias in the results, and each digit should be
 * uniformly distributed in 0-9.
*/
static uint64_t quintillion(void)
{
    uint64_t result;

    do {
        result = xorshift_u64() & UINT64_C(1152921504606846975);
    } while (!result || result > UINT64_C(1000000000000000000));

    return result - UINT64_C(1);
}

/* This function returns a single uniformly random digit.
*/
static unsigned char digit(void)
{
    static uint64_t       digits_cache = 0;
    static unsigned char  digits_cached = 0;
    unsigned char         retval;

    if (!digits_cached) {
        digits_cache = quintillion();
        digits_cached = 17; /* We steal the first one! */
    } else
        digits_cached--;
    
    retval = digits_cache % (uint64_t)(10);
    digits_cache /= (uint64_t)(10);

    return retval;
}

static int parse_ulong(const char *src, unsigned long *to)
{
    const char   *end = src;
    unsigned long value;

    if (!src)
        return errno = EINVAL;

    errno = 0;
    value = strtoul(src, (char **)&end, 0);
    if (errno)
        return errno;

    if (end == src)
        return errno = EINVAL;
    while (*end)
        if (isspace(*end))
            end++;
        else
            return errno = EINVAL;

    if (to)
        *to = value;
    return 0;
}

int main(int argc, char *argv[])
{
    unsigned long lines, cols, line, col, seed;
    
    /* When parsing the command-line parameters,
     * use locale conventions. */
    setlocale(LC_ALL, "");

    /* Standard output should be fully buffered, if possible.
     * This only affects output speed, so we're not too worried
     * if this happens to fail. */
    (void)setvbuf(stdout, NULL, _IOFBF, (size_t)IO_BLOCK_SIZE);

    if (argc < 3 || argc > 4 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
        fprintf(stderr, "\n");
        fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]);
        fprintf(stderr, "       %s COLS LINES [ SEED ]\n", argv[0]);
        fprintf(stderr, "\n");
        fprintf(stderr, "This program generates random decimal digits\n");
        fprintf(stderr, "0 - 9, separated by spaces, COLS per line,\n");
        fprintf(stderr, "LINES lines.  In total, COLS*LINES*2 bytes\n");
        fprintf(stderr, "will be used.\n");
        fprintf(stderr, "\n");
        fprintf(stderr, "SEED is the optional seed for the Xorshift64*\n");
        fprintf(stderr, "pseudo-random number generator used in this program.\n");
        fprintf(stderr, "If omitted, current time is used as the seed.\n");
        fprintf(stderr, "\n");
        return EXIT_SUCCESS;
    }

    if (parse_ulong(argv[1], &cols) || cols < 1UL) {
        fprintf(stderr, "%s: Invalid number of digits per line.\n", argv[1]);
        return EXIT_FAILURE;
    }
    if (parse_ulong(argv[2], &lines) || lines < 1UL) {
        fprintf(stderr, "%s: Invalid number of lines.\n", argv[2]);
        return EXIT_FAILURE;
    }

    if (argc > 3) {
        if (parse_ulong(argv[3], &seed)) {
            fprintf(stderr, "%s: Invalid Xorshift64* seed.\n", argv[3]);
            return EXIT_FAILURE;
        }
    } else
        seed = time_seed();

    /* Since zero seed is invalid, we map it to ~0. */
    xorshift_state = seed;
    if (!xorshift_state)
        xorshift_state = ~(uint64_t)0;

    /* Discard first 1000 values to make the initial values unpredictable. */
    for (col = 0; col < 1000; col++)
        xorshift_u64();

    for (line = 0UL; line < lines; line++) {
        fputc('0' + digit(), stdout);
        for (col = 1UL; col < cols; col++) {
            fputc(' ', stdout);
            fputc('0' + digit(), stdout);
        }
        fputc('\n', stdout);

        /* Check for write errors. */
        if (ferror(stdout))
            return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

fwrite()ラインバッファに切り替えて一度に 1 つずつ出力するのではなく、一度に 1 つずつ各数字を出力すると、より速く作成できます。出力がブロックデバイスの場合は、部分(2の累乗ではない)書き込みを防ぐためにストリームを完全にバッファリングしたままにします。

#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <locale.h>
#include <ctype.h>
#include <stdio.h>
#include <errno.h>
#include <time.h>

#if _POSIX_C_SOURCE-199309 >= 0
static uint64_t time_seed(void)
{
    struct timespec  ts;

    if (clock_gettime(CLOCK_REALTIME, &ts))
        return (uint64_t)time(NULL);

    return (uint64_t)ts.tv_sec
         ^ (((uint64_t)ts.tv_nsec) << 32);
}
#else
static uint64_t time_seed(void)
{
    return (uint64_t)time(NULL);
}
#endif

/* Preferred output I/O block size.
 * Currently, about 128k blocks yield
 * maximum I/O throughput on most devices.
 * Note that this is a heuristic value,
 * and may be increased in the future.
*/
#ifndef  IO_BLOCK_SIZE
#define  IO_BLOCK_SIZE  262144
#endif

/* This is the Xorshift* pseudo-random number generator.
 * See https://en.wikipedia.org/wiki/Xorshift#xorshift.2A
 * for details. This is an incredibly fast generator that
 * passes all but the MatrixRank test of the BigCrush
 * randomness test suite, with a period of 2^64-1.
 * Note that neither xorshift_state, nor the result of
 * this function, will ever be zero.
*/
static uint64_t xorshift_state;

static uint64_t xorshift_u64(void)
{
    xorshift_state ^= xorshift_state >> 12;
    xorshift_state ^= xorshift_state << 25;
    xorshift_state ^= xorshift_state >> 27;
    return xorshift_state * UINT64_C(2685821657736338717);
}

/* This function returns a number between (inclusive)
 * 0 and 999,999,999,999,999,999 using xorshift_u64()
 * above, using the exclusion method. Thus, there is
 * no bias in the results, and each digit should be
 * uniformly distributed in 0-9.
*/
static uint64_t quintillion(void)
{
    uint64_t result;

    do {
        result = xorshift_u64() & UINT64_C(1152921504606846975);
    } while (!result || result > UINT64_C(1000000000000000000));

    return result - UINT64_C(1);
}

/* This function returns a single uniformly random digit.
*/
static unsigned char digit(void)
{
    static uint64_t       digits_cache = 0;
    static unsigned char  digits_cached = 0;
    unsigned char         retval;

    if (!digits_cached) {
        digits_cache = quintillion();
        digits_cached = 17; /* We steal the first one! */
    } else
        digits_cached--;
    
    retval = digits_cache % (uint64_t)(10);
    digits_cache /= (uint64_t)(10);

    return retval;
}

static int parse_ulong(const char *src, unsigned long *to)
{
    const char   *end = src;
    unsigned long value;

    if (!src)
        return errno = EINVAL;

    errno = 0;
    value = strtoul(src, (char **)&end, 0);
    if (errno)
        return errno;

    if (end == src)
        return errno = EINVAL;
    while (*end)
        if (isspace(*end))
            end++;
        else
            return errno = EINVAL;

    if (to)
        *to = value;
    return 0;
}

int main(int argc, char *argv[])
{
    unsigned long lines, cols, line, col, seed;
    char         *oneline;
    
    /* When parsing the command-line parameters,
     * use locale conventions. */
    setlocale(LC_ALL, "");

    /* Standard output should be fully buffered, if possible.
     * This only affects output speed, so we're not too worried
     * if this happens to fail. */
    (void)setvbuf(stdout, NULL, _IOFBF, (size_t)IO_BLOCK_SIZE);

    if (argc < 3 || argc > 4 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
        fprintf(stderr, "\n");
        fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]);
        fprintf(stderr, "       %s COLS LINES [ SEED ]\n", argv[0]);
        fprintf(stderr, "\n");
        fprintf(stderr, "This program generates random decimal digits\n");
        fprintf(stderr, "0 - 9, separated by spaces, COLS per line,\n");
        fprintf(stderr, "LINES lines.  In total, COLS*LINES*2 bytes\n");
        fprintf(stderr, "will be used.\n");
        fprintf(stderr, "\n");
        fprintf(stderr, "SEED is the optional seed for the Xorshift64*\n");
        fprintf(stderr, "pseudo-random number generator used in this program.\n");
        fprintf(stderr, "If omitted, current time is used as the seed.\n");
        fprintf(stderr, "\n");
        return EXIT_SUCCESS;
    }

    if (parse_ulong(argv[1], &cols) || cols < 1UL) {
        fprintf(stderr, "%s: Invalid number of digits per line.\n", argv[1]);
        return EXIT_FAILURE;
    }
    if (parse_ulong(argv[2], &lines) || lines < 1UL) {
        fprintf(stderr, "%s: Invalid number of lines.\n", argv[2]);
        return EXIT_FAILURE;
    }

    if (argc > 3) {
        if (parse_ulong(argv[3], &seed)) {
            fprintf(stderr, "%s: Invalid Xorshift64* seed.\n", argv[3]);
            return EXIT_FAILURE;
        }
    } else
        seed = time_seed();

    /* Since zero seed is invalid, we map it to ~0. */
    xorshift_state = seed;
    if (!xorshift_state)
        xorshift_state = ~(uint64_t)0;

    /* Discard first 1000 values to make the initial values unpredictable. */
    for (col = 0; col < 1000; col++)
        xorshift_u64();

    /* Allocate memory for a full line. */
    oneline = malloc((size_t)(2 * cols + 1));
    if (!oneline) {
        fprintf(stderr, "Not enough memory for %lu column buffer.\n", cols);
        return EXIT_FAILURE;
    }

    /* Set spaces and terminating newline. */
    for (col = 0; col < cols; col++)
        oneline[2*col + 1] = ' ';
    oneline[2*cols-1] = '\n';

    /* Not needed, but in case a code modification treats it as a string. */
    oneline[2*cols] = '\0';

    for (line = 0UL; line < lines; line++) {
        for (col = 0UL; col < cols; col++)
            oneline[2*col] = digit();

        if (fwrite(oneline, 2*cols, 1, stdout) != 1)
            return EXIT_FAILURE; 
    }

    /* Check for write errors. */
    if (ferror(stdout))
        return EXIT_FAILURE;

    return EXIT_SUCCESS;
}

注:両方の例は2016年11月18日に編集されました。確実にする数値の均一な分布(ゼロを除く、たとえばここさまざまな疑似乱数ジェネレータの比較と詳細情報)

たとえば、次のようにコンパイルします。

gcc -Wall -O2 decimal-digits.c -o decimal-digits

オプションで、システム全体にインストールして/usr/bin使用できます。

sudo install -o root -g root -m 0755 decimal-digits /usr/bin

1行あたりのビット数と行数が必要です。1000000000 / 100 / 2 = 5000000(500万、合計バイトを列数で割った値を2で割った値)なので、次のように使用できます。

./decimal-digits 100 5000000 > digits.txt

digits.txtOPの要件に応じて、ギガバイトサイズのデータ​​を生成します。

プログラム自体は、効率性ではなく読みやすくするために書かれています。ここで私の目的は、コードの効率を示すことではありません。とにかく、私は通常のCインターフェイスの代わりにPOSIX.1と低レベルI / Oを使用します。単一行コード、ショートシェル、または awk スクリプトレットの取り組みを開発関連のツールやパフォーマンスと比較します。

GNU Cライブラリを使用すると、各文字出力のオーバーヘッド(間接関数呼び出しまたは条件文 - ご覧のように、インターフェイスは実際には非常に複雑で一般的です)fputc()がほとんどありません。FILEこの特定のIntel Core i5-4200Uノートブックでは、出力を/dev/null最初の(fputc)バージョンにリダイレクトするのに約11秒かかりますが、一度に1行のバージョンは1.3秒しかかかりません。

私は巨大なデータセットで作業するのが好きなので、このようなプログラムやジェネレータをよく書いています。私にとってこれは奇妙です。たとえば、解析時に正確に同じ値を生成するのに十分な精度で、すべての有限正数IEEE-754浮動小数点値をテキストファイルに印刷するプログラムを書いたことがあります。ファイルサイズは数ギガバイト(おそらく4G程度)です。有限正数はfloat思ったほど大きくありません。私はそれを使用してそのようなデータを読み取って解析する実装を比較します。

OPなどの一般的なユースケースでは、シェルスクリプト、スクリプトレット、およびシングルライナーがより良いアプローチです。全体の作業を完了するのに時間がかかりません。 (毎日他のファイルが必要な人や他のファイルが必要な人が多い場合を除き、上記の専用ツールを使用することはそれほど価値があるかもしれません。)

答え3

お持ちの場合shuf利用可能です(最近のGNU coreutilsでは可能です)。次のことができます。

time shuf -r -n $((512*1024*1024)) -i 0-9 | paste -sd "$(printf '%99s\\n')" -

私の仮想マシンでは、Stéphaneの答えより約3:4遅くなりました。

答え4

シンプルでわかりやすいソリューションであることを願っています。

od -An -x /dev/urandom | tr -dc 0-9 | fold -w100 | awk NF=NF FS= | head -c1G
  • odここで16進数の統合ストリームを作成します/dev/random
  • tr文字を削除して0-9数字だけを保持
  • fold各行に100個の数字があることを確認してください。
  • awk行内にスペースを挿入する
  • head入力を1GBに切ります。

関連情報