Argument list too long
Hatayla karşılaştığınızda akılda tutulması gereken 3 önemli nokta vardır :
Komut satırı argümanlarının uzunluğu, POSIX tanımına göre "... [m] çevre verisi de dahil olmak üzere çalıştırma işlevlerinin maksimum argüman uzunluğu" ARG_MAX
olan değişkenle sınırlıdır . -built-it komutu, bu komutun işleminin ortaya çıkması için birini çağırmak zorundadır ve o zaman devreye girer, ayrıca komutun kendisine verilen ad veya yol (örneğin ) bir rol oynar.exec()
ARG_MAX
/bin/echo
Kabuk yerleşik komutları kabuk tarafından yürütülür, yani kabuğun exec()
işlev ailesini kullanmadığı ve bu nedenle ARG_MAX
değişkenden etkilenmediği anlamına gelir .
Gibi xargs
ve değişkenlerinin find
farkında olan bazı komutlar ARG_MAX
ve art arda bu sınırın altındaki işlemleri gerçekleştirir
Yukarıdaki noktalardan ve Kusalananda'nın konuyla ilgili mükemmel cevabında gösterildiği gibi Argument list too long
, çevre büyük olduğunda da ortaya çıkabilir. Bu nedenle, her bir kullanıcının ortamının değişebileceğini ve bayt cinsinden argüman boyutunun alakalı olduğunu dikkate alarak tek bir dosya / argüman bulmak zor.
Böyle bir hata nasıl ele alınır?
Önemli olan dosya sayısına değil, kullanacağınız komutun exec()
işlev ailesini ve teğetsel olarak - yığın alanını içerip içermediğine odaklanmaktır .
Kabuk yerleşiklerini kullan
Daha önce tartışıldığı gibi, kabuk yapıları ARG_MAX
sınırlamaya karşı bağışıklık kazanır, yani for
döngü, while
döngü, yerleşik echo
ve yerleşik gibi şeyler printf
- hepsi yeterince iyi performans gösterir.
for i in /path/to/dir/*; do cp "$i" /path/to/other/dir/; done
On ilgili soruya dosyaları silme hakkında gibi bir çözüm vardı:
printf '%s\0' *.jpg | xargs -0 rm --
Bu kabuğun yerleşik kullandığını unutmayın printf
. Eğer dış diyoruz printf
, buna dahil olacak exec()
, dolayısıyla çok sayıda argümanla başarısız olacaksınız:
$ /usr/bin/printf "%s\0" {1..7000000}> /dev/null
bash: /usr/bin/printf: Argument list too long
bash dizileri
Göre bir cevap jlliagre göre, bash
danjpreron en gösterildiği gibi dosya isimleri dizi yapı ve halka yineleme başına dilimleri kullanılarak, böylece dizilerin ilgili sınırlar yoktur, sıra yapılabilir cevap :
files=( /path/to/old_dir/*.prj )
for((I=0;I<${#files[*]};I+=1000)); do
cp -t /path/to/new_dir/ "${files[@]:I:1000}"
done
Bununla birlikte, bunun bash-özgü ve POSIX-dışı olma sınırlaması vardır.
Yığın alanını arttır
Bazen insanlar önermek görebilirsiniz yığın alanı artan ile ulimit -s <NUM>
; Linux'ta ARG_MAX değeri, her program için yığın alanının 1 / 4'üdür; bu, yığın alanını arttırmanın, bağımsız değişkenler için alanı orantılı olarak artırdığı anlamına gelir.
# getconf reports value in bytes, ulimit -s in kilobytes
$ getconf ARG_MAX
2097152
$ echo $(( $(getconf ARG_MAX)*4 ))
8388608
$ printf "%dK\n" $(ulimit -s) | numfmt --from=iec --to=none
8388608
# Increasing stack space results in increated ARG_MAX value
$ ulimit -s 16384
$ getconf ARG_MAX
4194304
Göre Franck Dernoncourt tarafından cevap Linux Journal değinir, bir de gerekenden daha fazla iş var ve belirtilen açıkları için potansiyel açar ancak bağımsız değişkenler için maksimum bellek sayfalarının için büyük değere sahip Linux çekirdeği yeniden derleme Linux Journal makaleye atıf olabilir.
Kabuk önlemek
Başka bir yol, kullanmak python
veya python3
varsayılan olarak Ubuntu ile birlikte gelen kullanmaktır . Aşağıdaki python + here-doc örneği, 40.000 öğe aralığında bir yerde büyük bir dosya dizinini kopyalamak için şahsen kullandığım bir şeydir:
$ python <<EOF
> import shutil
> import os
> for f in os.listdir('.'):
> if os.path.isfile(f):
> shutil.copy(f,'./newdir/')
> EOF
Özyinelemeli geçişler için os.walk kullanabilirsiniz .
Ayrıca bakınız: