“Bağımsız değişken listesi çok uzun”: Komutumu değiştirmeden bununla nasıl başa çıkabilirim?


18

Gibi bir komut çalıştırdığımda ls */*/*/*/*.jpghatayı alıyorum

-bash: /bin/ls: Argument list too long

Bunun neden olduğunu biliyorum: Bunun nedeni, bir komuta argümanlar için alan miktarında bir çekirdek sınırı olmasıdır. Standart tavsiye, argümanlar için çok fazla alan gerektirmemesi için kullandığım komutu değiştirmektir (örn., findVe xargs).

Komutu değiştirmek istemezsem ne olur? Aynı komutu kullanmaya devam etmek istersem ne olur? Bu hatayı almadan işleri nasıl "sadece çalışır" hale getirebilirim? Hangi çözümler mevcut?


Yararlı okuma: Bash SSS 95 . Komutunuzu değiştirmeden, argüman listesi maksimum boyutunu artırmak için yeniden derlemenin yanı sıra dizin yapınızı değiştirmek için yapabileceğiniz çok şey yoktur, böylece daha az dosya olur.
jw013

1
@ jw013, linux çekirdek sürümüne bağlı olarak, bağımsız değişken listesini artırmak mümkün olabilir - son sistemlerde değişiklik hakkında ayrıntılar için bkz. unix.stackexchange.com/a/45161/8979 .
Ulrich Dangel

@UlrichDangel, Evet, bu mümkün! Cevabımı görün; cevabım bunun nasıl yapılacağını gösteriyor (Linux'ta, yeterince yeni bir çekirdeğe sahip).
DW

Yanıtlar:


27

Linux'ta, komut bağımsız değişkenleri için maksimum alan miktarı, kullanılabilir yığın alanı miktarının 1 / 4'üdür. Bu nedenle, bir çözüm, yığın için kullanılabilir alan miktarını arttırmaktır.

Kısa versiyon: gibi bir şey çalıştırın

ulimit -s 65536

Daha uzun sürüm: Yığın için kullanılabilir varsayılan alan miktarı 8192 KB gibi bir şeydir. Kullanılabilir alan miktarını aşağıdaki gibi görebilirsiniz:

$ ulimit -s
8192

Daha büyük bir sayı seçin ve yığın için kullanılabilir alan miktarını ayarlayın. Örneğin, yığın için 65536 KB'a kadar izin vermeye çalışmak istiyorsanız, şunu çalıştırın:

$ ulimit -s 65536

Deneme yanılma yöntemini kullanarak bunun ne kadar büyük olması gerektiğiyle uğraşmanız gerekebilir. Birçok durumda, bu sözdizimi dışarı komuta ve işi değiştirme ihtiyacını ortadan kaldıracak bir kirli hızlı ve-çözümdür find, xargs(bunu yaparken diğer faydaları vardır fark olsa da), vb.

Bunun Linux'a özgü olduğuna inanıyorum. Muhtemelen başka bir Unix işletim sisteminde (test edilmemiştir) yardımcı olmayacağından şüpheleniyorum.


1
Bu şekilde çalıştığını doğrulayabilirsiniz: $ getconf ARG_MAX 2097152 $ ulimit -s 65535 $ getconf ARG_MAX 16776960
Alex

3

Bu Linux Journal makalesi 4 çözüm sunuyor. Sadece dördüncü çözüm komutun değiştirilmesini içermez:

Yöntem # 4, komut satırı bağımsız değişkenleri için çekirdek içinde ayrılan sayfa sayısını el ile artırmayı içerir. İnclude / linux / binfmts.h dosyasına bakarsanız, en üstte aşağıdakileri bulabilirsiniz:

/*
 * MAX_ARG_PAGES defines the number of pages allocated for   arguments
 * and envelope for the new program. 32 should suffice, this gives
 * a maximum env+arg of 128kB w/4KB pages!
 */
#define MAX_ARG_PAGES 32

Komut satırı bağımsız değişkenlerine ayrılmış bellek miktarını artırmak için, MAX_ARG_PAGES değerini daha yüksek bir sayı ile girmeniz yeterlidir. Bu düzenleme kaydedildikten sonra, normal şekilde yaptığınız gibi yeni çekirdeği yeniden derleyin, yükleyin ve yeniden başlatın.

Kendi test sistemimde, bu değeri 64'e yükselterek tüm sorunlarımı çözmeyi başardım. Kapsamlı testlerden sonra, geçişten beri tek bir sorunla karşılaşmadım. MAX_ARG_PAGES64 olarak ayarlanmış olsa bile, üretebildiğim en uzun komut satırı, bugünün sistem donanım standartlarına göre çok fazla değil, sadece 256 KB sistem belleği kaplayacağı için tamamen bekleniyor .

Yöntem # 4'ün avantajları açıktır. Artık komutu normalde yaptığınız gibi çalıştırabilirsiniz ve başarıyla tamamlanır. Dezavantajları da aynı derecede açıktır. Komut satırı için kullanılabilir bellek miktarını kullanılabilir sistem belleği miktarının ötesine yükseltirseniz, kendi sisteminizde bir DOS saldırısı oluşturabilir ve çökmesine neden olabilirsiniz. Özellikle çok kullanıcılı sistemlerde, küçük bir artış bile önemli bir etkiye sahip olabilir, çünkü daha sonra her kullanıcıya ek bellek tahsis edilir. Bu nedenle, Yöntem # 4'ün sizin için uygun bir seçenek olup olmadığını belirlemenin en güvenli yolu olduğundan, her zaman kendi ortamınızda kapsamlı bir şekilde test edin.

Bu sınırlamanın ciddi derecede can sıkıcı olduğunu kabul ediyorum.


2

Bunun yerine şunu ls */*/*/*/*.jpgdeneyin:

echo */*/*/*/*.jpg | xargs ls

xargs(1) sistemdeki maksimum bağımsız değişken sayısının ne olduğunu bilir ve belirtilen komut satırını, bu sınırdan daha fazla bağımsız değişken olmadan birden fazla kez çağırmak için standart girişini böler (ne olursa olsun OS ' -nseçeneğini kullanarak maksimum ).

Örneğin, sınırın 3 bağımsız değişken olduğunu ve beş dosyanız olduğunu varsayalım. Bu durumda iki kez xargsyürütülür ls:

  1. ls 1.jpg 2.jpg 3.jpg
  2. ls 4.jpg 5.jpg

Genellikle bu tamamen uygundur, ancak her zaman değil - örneğin, her bir girişin sizin için düzgün bir şekilde sıralanmasınals (1) güvenemezsiniz , çünkü her ayrı davet, yalnızca kendisine verilen girişlerin alt kümesini sıralayacaktır .lsxargs

Sınırı başkaları tarafından önerildiği gibi çarpabilmenize rağmen, yine de bir sınır olacaktır - ve bir gün JPG koleksiyonunuz tekrar büyüyecektir. Senaryo (lar) ınızı sonsuz bir sayı ile başa çıkmak için hazırlamalısınız ...


Fikir için teşekkürler! Bu kötü bir çözüm değil. İki uyarı: 1. Bu, adında boşlukları olan dizinleri ve dosya adlarını bozar, bu yüzden mükemmel bir yedek değildir. 2. Bu mermilerle aynı meseleyle karşılaşacak mı Argument list too long, echobunun yerine lsmermiler üzerinde echoyerleşik bir komut olmayan bir yerde mi? (Belki de bu çoğu mermide sorun değildir, bu yüzden önemsizdir.)
DW

1
Evet, dosya adlarındaki özel karakterler bir sorundur. Yapabileceğiniz en iyi şey kullanmaktır findile -print0içine çıktı ve boru - yüklemi xargsile -0seçeneği. echoyerleşik bir kabuktur ve exec(3) 'ün komut satırı sınırlamasından muzdarip değildir .
Mikhail T.
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.