CP: argumen jumlah file sumber maks untuk utilitas salin

11

Pertimbangkan bahwa ada banyak file di bawah / src /

cp /src/* /dst/

Berapa banyak file yang cpakan berhasil diproses?

Mike
sumber
2
Jika daftar argumen terlalu panjang (ingat, apa * yang diperbesar ke daftar semua file yang cocok dengan bola dunia), Anda dapat menyiasatinya dengan menggunakan misalnya IFS="\n" for file in /src/*; do mv "$file" /dst/; doneatau rsync -a /src/ /dst/.
DopeGhoti

Jawaban:

18

Itu sangat tergantung pada sistem dan versi, pada jumlah dan ukuran argumen dan pada jumlah dan ukuran nama variabel lingkungan.

Secara tradisional pada Unix, batas (seperti yang dilaporkan oleh getconf ARG_MAX) lebih atau kurang pada ukuran kumulatif:

  • Panjang string argumen (termasuk terminating '\0')
  • Panjang array pointer ke string tersebut, jadi biasanya 8 byte per argumen pada sistem 64bit
  • Panjang string lingkungan (termasuk terminating '\0'), string lingkungan sedang dengan sesuatu seperti konvensi var=value.
  • Panjang array pointer ke string tersebut, jadi biasanya 8 byte per argumen pada sistem 64bit

Mengingat yang cpjuga dianggap sebagai argumen (adalah argumen pertama).

Di Linux, itu tergantung pada versinya. Perilaku di sana berubah baru-baru ini di mana itu bukan lagi ruang tetap.

Memeriksa di Linux 3.11, getconf ARG_MAXsekarang melaporkan seperempat dari batas yang ditetapkan pada ukuran stack, atau 128kiB jika itu kurang dari 512kiB).

( zshsintaksis di bawah):

$ limit stacksize
stacksize       8MB
$ getconf ARG_MAX
2097152
$ limit stacksize 4M
$ getconf ARG_MAX
1048576

Batas itu adalah pada ukuran kumulatif argumen dan string lingkungan dan beberapa overhead (saya menduga karena pertimbangan penyelarasan pada batas halaman). Ukuran pointer tidak diperhitungkan.

Mencari batas, saya dapatkan:

$ /bin/true {1..164686}
$ /bin/true {1..164687}
zsh: argument list too long: /bin/true
$ x= /bin/true {1..164686}
$ x=1 /bin/true {1..164686}
zsh: argument list too long: /bin/true

Ukuran kumulatif maksimum sebelum melanggar dalam hal itu adalah:

$ (env _=/bin/true x=;print -l /bin/true {1..164686}) | wc -c
1044462

Sekarang, itu tidak berarti bahwa Anda dapat melewati 1 juta argumen kosong. Pada sistem 64 bit, 1 juta argumen kosong membuat daftar penunjuk 8MB, yang akan berada di atas ukuran tumpukan 4MiB.

$ IFS=:; /bin/true ${=${(l.1000000..:.)${:-}}}
zsh: killed     /bin/true ${=${(l.1000000..:.)${:-}}}

(Anda akan melihat itu bukan kesalahan E2BIG. Saya tidak yakin pada titik mana proses tersebut terbunuh di sana, apakah itu ada dalam execvepanggilan sistem atau yang lebih baru).

Perhatikan juga (masih di Linux 3.11) bahwa ukuran maksimum argumen tunggal atau string lingkungan adalah 128kiB, terlepas dari ukuran stack.

$ /bin/true ${(l.131071..a.)${:-}} # 131072 OK
$ /bin/true ${(l.131072..a.)${:-}} # 131073 not
zsh: argument list too long: /bin/true
$ /bin/true ${(l.131071..a.)${:-}} ${(l.131071..a.)${:-}} # 2x 131072 OK
Stéphane Chazelas
sumber
Bisakah Anda berbagi tolong, bagaimana Anda menghasilkan 164686angka? yaitu bagaimana Anda menghitung urutan itu akan berada di bawah 2097152ukuran ARG_MAX?
Sergiy Kolodyazhnyy
14

Itu akan tergantung pada nilai ARG_MAX yang dapat berubah antar sistem. Untuk mengetahui nilai untuk menjalankan sistem Anda (menunjukkan hasil pada tambang sebagai contoh):

$ getconf ARG_MAX
2097152

Ini tidak ada hubungannya dengan cpatau shell Anda, itu adalah batas yang ditentukan oleh kernel, itu tidak akan menjalankan ( exec()) perintah jika argumen mereka lebih panjang dari ARG_MAX. Jadi, jika panjang daftar argumen yang Anda berikan cplebih besar dari ARG_MAX, cpperintah tidak akan berjalan sama sekali.

Untuk menjawab pertanyaan utama Anda, maka tidak cpakan memproses file karena tidak akan pernah dieksekusi dengan banyak argumen. Saya juga harus menyebutkan bahwa ini tidak tergantung pada jumlah argumen tetapi pada panjangnya. Anda mungkin bisa memiliki masalah yang sama dengan nama file yang sangat sedikit tetapi sangat panjang.


Cara mengatasi kesalahan ini adalah dengan menjalankan perintah Anda dalam satu lingkaran:

for file in /src/*; do cp "$file" /dst/; done
terdon
sumber
Apakah ini berarti bahwa bahasa tingkat yang lebih rendah seperti Cdapat memiliki masalah dengan ARG_MAX dan nama file yang sangat panjang?
Harold Fischer