いくつかの実験のために大容量ファイルを生成したいと思います。
これは私のスクリプトです。ファイルを作成して変数として読み込み、ループ内で定義された回数だけファイルに書き込もうとします。
#! /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
- 正確なバイト数を得る別の方法(たとえ一度だけ発生するのでどちらにも大きな差はない)- これらすべてが
echo
1000をカウントしたときに約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
生成されたデータのみをインポートすることです。その間、どこかでどこかで余分なバイト(暗黙の改行?)を探しているようです$( )
。<<<
この問題を解決します。やや面倒なことは認めます。ランダムデータのサイズがランダムまたは重要でない場合は、単純化できると確信しています。