parallel
別のツールや方法を使用して、多数のディレクトリをサブディレクトリに分割する作業を並列化したいと考えています。
例えば、コンテンツのあるディレクトリが 1,000,000 個ありますが、1 つのディレクトリでは多すぎるので、メイン ディレクトリに 10 個のディレクトリを作成し、それぞれに 100,000 個の元のディレクトリを移動します。日付による並べ替えも使用したいと考えています。すでに質問しました。同様の質問はこちらただし、これは重複ではありません。新しいコマンドを試して新しい結果が得られ、質問を書き直したからです。
それで、私はすでにこれを試しました
ls -tr|parallel -n100000 mkdir "dir_{#}"\;mv {} "dir_{#}"
この
ls -tr | parallel -j10 -n100000 --no-notice -k 'mkdir -p dir_{#}; mv {} -t dir_{#}'
コマンドを実行しましたが、1 つのサブディレクトリに約 10,000 個しか移動されず (場合によっては約 6,200 個、場合によっては約 12,500 個)、サブディレクトリが多すぎます (必要な数の 10 倍になることもあります)。
これも使ってみました:
ls -dtr * | parallel -j10 -n100000 --no-notice -k 'mkdir -p dir_{#}; mv {} -t dir_{#}'
しかし、それは与えましたbash: /bin/ls: Argument list too long
。
もちろん、各サブディレクトリにちょうど100,000個のディレクトリが必要なわけではなく、101,000個や98,500個のディレクトリでもかまいません。100,000の範囲の数値である必要があります。
このタスクを並列またはを使用して実行するにはどうすればよいですかparallel
?
答え1
問題は、シェル展開後にコマンドラインが取得できるバイト数の上限があることです。この制限はシステムの制限に依存します。
getconf ARG_MAX
mv {}
したがって、最大制限に達すると、入力ファイル名の長さに応じて引数の数が変化することになります。
並列使用を諦めずにこの制限を回避する解決策は、タスクを2つの段階に分割することです。
ls -tr | parallel -N 100000 --pipe -k "mkdir dir_{#}; parallel -X mv -t dir_{#}"
説明
--pipe
最初の段階では、stdinを指定された数に分割するオプションを使用します。小さい標準入力それぞれオプションで指定されたn行を含みます-N
。この例を使用して効果を確認できます。seq 1000000 | parallel -N 100000 --pipe wc -l
100000のマークで正確に分割されます
100000 100000 100000 ...
第二段階では、内側の平行線が小さい標準入力ジョブを実行するための新しい標準入力として、
-X
オプションはコマンドラインの長さが許す限り多くの引数を挿入します。mkdir dir_{#}; parallel -X mv -t dir_{#}
答え2
parallel
この問題は、大量の IO を扱っています。この状況でそれが本当に役立つかどうかは疑問です。
とにかく、「伝統的な」アプローチを検討することをお勧めします。
mkdir dir_{1..10}
ls -tr | nl | \
awk '$2 !~ /^dir_/ {i=1+int($1/100000); print $2 | "xargs mv -t dir_"i}'
どこ
ls -tr | nl
ディレクトリを日付順に並べ替え、補助ディレクトリ番号を追加します$2 !~ /^dir_/
作成されたばかりのフォルダーをスキップするために使用されます。i=1+int($1/100000)
dir-numberに基づいてフォルダ番号を計算しますprint $2 | "xargs mv -t dir_"i
プロセス増殖なしの動き
可能であれば、それぞれの時間も比較してください: time ....
(そして結果を私たちと共有してください☺)