たとえば、私のディレクトリには、次のように生成された複数のファイルが含まれています。
touch files/{1..10231}_file.txt
私はそれらを新しいディレクトリに移動したいと思いますnew_files_dir
。
最も簡単な方法は次のとおりです。
for filename in files/*; do
mv "${filename}" -t "new_files_dir"
done
このスクリプトは以下で動作します。10私のコンピュータから数秒。非常に遅いです。各ファイルに対するコマンドの実行により、mv
速度が遅くなります。
###修正開始###
私の場合、最も簡単な方法
mv files/* -t new_files_dir
または、「パラメータリストが長すぎます」の場合:
printf '%s\0' files/* | xargs -0 mv -t new_files_dir
しかし、上記のケースはミッションの一部です。全体的な作業は次の質問にあります。Linuxでは、ファイル名に基づいて多数のファイルをディレクトリに移動する。したがって、ファイルをそのサブディレクトリに移動する必要があり、サブディレクトリの対応はファイル名の番号に基づいています。これはfor
私のコードスニペットで繰り返しやその他の奇妙な現象の原因です。
###編集終了###
mv
次のように、単一ファイルではなく複数のファイルをコマンドに渡すことで、このプロセスを高速化できます。
batch_num=1000
# Counting of files in the directory
shopt -s nullglob
file_list=(files/*)
file_num=${#file_list[@]}
# Every file's common part
suffix='_file.txt'
for((from = 1, to = batch_num; from <= file_num; from += batch_num, to += batch_num)); do
if ((to > file_num)); then
to="$file_num"
fi
# Generating filenames by `seq` command and passing them to `xargs`
seq -f "files/%.f${suffix}" "$from" "$to" |
xargs -n "${batch_num}" mv -t "new_files_dir"
done
この場合、スクリプトは次のように動作します。0.2第二。したがって、パフォーマンスは50倍向上します。
しかし、問題があります。このファイル名のセットが最大許容長より小さいという保証はないため、いつでも「パラメータリストが多すぎる」ため、プログラムは動作を拒否する可能性があります。
私の考え計算は次のとおりですbatch_num
。
batch_num = "max allowable length" / "longest filename length"
その後batch_num
で使用してくださいxargs
。
したがって、質問:許容される最大長はどのように計算されますか?
私はいくつかのことをしました:
全長は以下で確認できます。
$ getconf ARG_MAX 2097152
環境変数もパラメータサイズに影響を与えるため、次の値を除く必要があります
ARG_MAX
。$ env | wc -c 3403
正しい値を見つける前に、異なる数のファイルを試して同じサイズの最大ファイル数を決定する方法(バイナリ検索を使用)が開発されました。
function find_max_file_number { right=2000000 left=1 name=$1 while ((left < right)); do mid=$(((left + right) / 2)) if /bin/true $(yes "$name" | head -n "$mid") 2>/dev/null; then left=$((mid + 1)) else right=$((mid - 1)) fi done echo "Number of ${#name} byte(s) filenames:" $((mid - 1)) } find_max_file_number A find_max_file_number AA find_max_file_number AAA
出力:
Number of 1 byte(s) filenames: 209232 Number of 2 byte(s) filenames: 190006 Number of 3 byte(s) filenames: 174248
しかし、私はこれらの結果の論理/関係を理解できませんでした。
この値が試行されました。回答計算には適していません。
書いた氏プログラムは、渡されたパラメーターの合計サイズを計算します。このプログラムの結果は似ていますが、計算されていないバイトが残ります。
$ ./program {1..91442}_file.txt arg strings size: 1360534 number of pointers to strings 91443 argv size: 1360534 + 91443 * 8 = 2092078 envp size: 3935 Overall (argv_size + env_size + sizeof(argc)): 2092078 + 3935 + 4 = 2096017 ARG_MAX: 2097152 ARG_MAX - overall = 1135 # <--- Enough bytes are # left, but no additional # filenames are permitted. $ ./program {1..91443}_file.txt bash: ./program: Argument list too long
プログラム.c
#include <stdio.h> #include <string.h> #include <unistd.h> int main(int argc, char *argv[], char *envp[]) { size_t chr_ptr_size = sizeof(argv[0]); // The arguments array total size calculation size_t arg_strings_size = 0; size_t str_len = 0; for(int i = 0; i < argc; i++) { str_len = strlen(argv[i]) + 1; arg_strings_size += str_len; // printf("%zu:\t%s\n\n", str_len, argv[i]); } size_t argv_size = arg_strings_size + argc * chr_ptr_size; printf( "arg strings size: %zu\n" "number of pointers to strings %i\n\n" "argv size:\t%zu + %i * %zu = %zu\n", arg_strings_size, argc, arg_strings_size, argc, chr_ptr_size, argv_size ); // The enviroment variables array total size calculation size_t env_size = 0; for (char **env = envp; *env != 0; env++) { char *thisEnv = *env; env_size += strlen(thisEnv) + 1 + sizeof(thisEnv); } printf("envp size:\t%zu\n", env_size); size_t overall = argv_size + env_size + sizeof(argc); printf( "\nOverall (argv_size + env_size + sizeof(argc)):\t" "%zu + %zu + %zu = %zu\n", argv_size, env_size, sizeof(argc), overall); // Find ARG_MAX by system call long arg_max = sysconf(_SC_ARG_MAX); printf("ARG_MAX: %li\n\n", arg_max); printf("ARG_MAX - overall = %li\n", arg_max - (long) overall); return 0; }
私はこのプログラムの正確性についてStackOverflowに質問しました:argv、envp、argc(コマンドライン引数)の最大要約サイズは、常にARG_MAX制限から離れています。。
ベストアンサー1
xargsに計算をさせます。
printf '%s\0' files/* | xargs -0 mv -t new_files_dir