時間 generateUserData.sh テスト {0..1000}

時間 generateUserData.sh テスト {0..1000}

いくつかの実験のために大容量ファイルを生成したいと思います。

これは私のスクリプトです。ファイルを作成して変数として読み込み、ループ内で定義された回数だけファイルに書き込もうとします。

#! /usr/bin/env bash

set -e
set -u

< /dev/urandom tr -dc "\t\n [:alnum:]" | head -c32768 > temp.txt
data=$(cat ./temp.txt)

for testdir in "$@"; do
    echo "create directory '$testdir'"
    mkdir -p $testdir
    for i in {1..3}; do
        counter=$(printf %02d $i)
        testfile=$testdir/test_${testdir##*/}_$counter.txt
        echo "create file '$testfile'"
        echo "$data" > $testfile
    done
done

このスクリプトを使用して3000ファイル(各フォルダに3つのファイルがあります)を作成しようとすると、システムは約19秒かかります。

時間 generateUserData.sh テスト {0..1000}

create directory 'TEST999'
create file 'TEST999/test_TEST999_01.txt'
create file 'TEST999/test_TEST999_02.txt'
create file 'TEST999/test_TEST999_03.txt'
create directory 'TEST1000'
create file 'TEST1000/test_TEST1000_01.txt'
create file 'TEST1000/test_TEST1000_02.txt'
create file 'TEST1000/test_TEST1000_03.txt'

real    0m19.333s
user    0m14.791s
sys     0m4.784s

echo私はこれが遅い部分かもしれないことを知っています。できるだけ早く彼を終わらせる方法についてのアイデアはありますか?

答え1

遅いプロセスでは、プロセスを分岐して外部コマンドを実行することをお勧めします。mkdir

counter=$(printf %02d $i)

また、bashでプロセスをフォークします。次のように書くことでこれを防ぐことができます。

printf -v counter %02d "$i"

または:

printf -v testfile %s/%s_%02d.txt "$testdir" "${testdir##*/}" "$i"

mkdirファイルごとに1つずつ実行するのではなく、1回の呼び出しですべてのディレクトリを作成します(mkdir -p -- "$@";忘れないでください)。--mkdir

次のいずれかに一時ファイルは必要ありません。

data=$(< /dev/urandom tr -dc "\t\n [:alnum:]" | head -c32768; echo .)
data=${data%.}

.コマンド置換が削除されるため、32768バイトを含めるようにするには追加が$data必要です。みんな末尾の改行文字。また、誰も追加されないechoことに注意してください。-n任意のデータの場合は、printfとにかく代わりに使用する必要があります。echo

また、head -c 32768文字ではなく32768バイトを提供するため、文字が途中で切り取られる可能性があります。

printf %s "$data" > "$file"

答え2

何かを我慢するスティーブン・チャジェラス彼らはいくつかの修正を加えた素晴らしい答えで言いました。

#!/usr/bin/env bash

set -e
set -u

main() {
  < /dev/urandom tr -dc "\t\n [:alnum:]" | dd iflag=fullblock of=./temp.txt bs=32K count=1
  mkdir -p -- "${@:?}"
  for testdir in "$@"; do
    for i in {1..3}; do
      printf "%s/%s_%02d.txt\n" "$testdir" "${testdir##*/}" "$i"
    done
  done | xargs -n1 -P${proc:-16} cp ./temp.txt
}

time main "${@}"

  • dd- 正確なバイト数を得る別の方法(たとえ一度だけ発生するのでどちらにも大きな差はない)
  • これらすべてがecho1000をカウントしたときに約3秒が追加されました。
  • マルチスレッド、実行時に調整可能(proc変数を介して) - システムに最適な値を見つけます。

例えば

proc=32 bash ./foo.sh {1..1000}

注 – 変数の入力に関する元の質問がインスタンスであると仮定します。XYの問題...もしはいこれは難しい要件であり、私の答えは書面で有効ではありません。

ただし、この変更により、次のことが必要です。

data="$(< /dev/urandom tr -dc "\t\n [:alnum:]" | dd iflag=fullblock bs=32K count=1)"
dd iflag=fullblock bs=32K count=1 of=./temp.txt <<<"${data}"

2番目は、dd生成されたデータのみをインポートすることです。その間、どこかでどこかで余分なバイト(暗黙の改行?)を探しているようです$( )<<<この問題を解決します。やや面倒なことは認めます。ランダムデータのサイズがランダムまたは重要でない場合は、単純化できると確信しています。

関連情報