Çok sayıda dosyayı kopyalarken 'Bağımsız değişken listesi çok uzun' hatası


12

Aşağıdaki komutu kullanıyorum:

\cp -uf /home/ftpuser1/public_html/ftparea/*.jpg /home/ftpuser2/public_html/ftparea/

Ve hatayı alıyorum:

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

Ayrıca denedim:

ls /home/ftpuser1/public_html/ftparea/*.jpg | xargs -I {} cp -uf {} /home/ftpuser2/public_html/ftparea/

Hala -bash: / bin / ls: Bağımsız değişken listesi çok uzun

Herhangi bir fikir?


Tüm jpgs 1 dizinden diğerine ama sadece yeni dosyalar ve güncelleştirilmiş olanlar kopyalamaya çalışıyorum.
icelizard

lsbu tür şeyler yapmak için tasarlanmamıştır. Kullanın find.
sonraki duyuruya kadar duraklatıldı.

Sorun ls ile değil, kabuğun ls'e ilettiği argümanların sayısı ile. Aynı hatayı vi veya yerleşik olmayan herhangi bir komutla alırsınız.
chris

Ama lsedilir özellikle bunun için tasarlanmamış: mywiki.wooledge.org/ParsingLs
bir sonraki duyuruya kadar durdurulmuş.

Doğru, ancak bu durumda hata ls ile bir ayrıştırma hatası nedeniyle değil, ls olan yeni bir sürece bir milyar argüman geçirmektir. Ls uygunsuz kullanımı olmasının yanı sıra, unix kaynak / tasarım sınırlamalarına çarpmak olur. Bu durumda, hastanın hem mide ağrısı hem de kırık bacağı vardır.
chris

Yanıtlar:


19

* .jpg, kabuğun işleyebileceğinden daha uzun bir listeye genişler. Bunun yerine deneyin

find  /home/ftpuser/public_html/ftparea/ -name "*.jpg" -exec cp -uf "{}" /your/destination \;

Find / home / ftpuser1 / public_html / ftparea / -name "* jpg" -exec cp -uf "{}" / home / ftpuser2 / public_html / ftparea / kullandım ve şu hatayı buldum: -exec
icelizard

Cevaplayıcının size söylediği doğru, cp'nin son argümanını kaçırıyorsunuz. Uygulamanızı iki kez kontrol edin. Bu yanıtta "* .jpg" içindeki noktanın eksik olduğunu unutmayın, bu hatalı davranışlara yol açabilir (örneğin "myjpg" adında bir dizin). Not sonra bu size tipi dosyasını kullanarak kopyalamak için gidiyor (dirs sembolik önlenmesi ve böylece etkilenecek üzerine) ne yakından belirtmek paranoya ama daha güvenli olabilir
drAlberT

Daha yakından inceledikten sonra “\;” -exec'in yürütmesi gereken komutu bitirmek için. Aptal bana!
icelizard

@AlberT: Kafalar eksik nokta için teşekkürler. Bu bir yazım hatasıydı. Yanıt güncellendi.
Shawn Chin

CP'nin üstesinden gelemeyeceği değil. Kabuk yapamaz.
d -_- b

6

Sistem komutları için bağımsız değişken listesinin ne kadar süre olabileceği konusunda maksimum bir sınır vardır - bu sınır, MAX_ARG_PAGESçekirdeğin ne zaman derlendiğine bağlı olarak distro-spesifiktir ve çekirdeği yeniden derlemeden değiştirilemez.

Globbing'in kabuk tarafından işlenme şekli nedeniyle, aynı argümanı ("* .jpg") kullandığınızda çoğu sistem komutunu etkiler. Glob önce kabuk tarafından işlendiğinden ve sonra komuta gönderildiğinden, komut:

cp -uf *.jpg /targetdir/

aslında yazdığınız gibi kabukla aynıdır:

cp -uf 1.jpg 2.jpg ... n-1.jpg n.jpg /targetdir/

Çok sayıda jpegs ile uğraşıyorsanız, bu çok hızlı bir şekilde yönetilemez hale gelebilir. Adlandırma kuralınıza ve gerçekten işlemeniz gereken dosya sayısına bağlı olarak, cp komutunu aynı anda dizinin farklı bir alt kümesinde çalıştırabilirsiniz :

cp -uf /sourcedir/[a-m]*.jpg /targetdir/
cp -uf /sourcedir/[n-z]*.jpg /targetdir/

Bu işe yarayabilir, ancak tam olarak ne kadar etkili olacağını, dosya listenizi uygun globbable bloklara ne kadar iyi bölebileceğinize bağlıdır.

Globbable. Bu kelimeyi seviyorum.

Gibi bazı komutlar, find ve xargs , acı büyüklüğünde argüman listeleri yapmadan büyük dosya listeleri işleyebilir.

find /sourcedir/ -name '*.jpg' -exec cp -uf {} /targetdir/ \;

-Exec bağımsız değişkeni, find ile bulunan her dosya için {} yerine bulunan her dosya adıyla komut satırının kalanını bir kez çalıştırır . Yana cp komutu yalnızca bir seferde bir dosya üzerinde çalıştırılır, argüman listesi sınırı bir sorun değildir.

Bu, her dosyayı ayrı ayrı işlemek zorunda kaldığından yavaş olabilir. Xargs kullanmak daha verimli bir çözüm sağlayabilir:

find /sourcedir/ -name '*.jpg' -print0 | xargs -0 cp -uf -t /destdir/

Xargs tarafından sağlanan tam dosya listesini alabilir bulmak ve yönetilebilir boyutlarda ve çalıştırma ait argümanı listeleri içine yıkmak cp bu sublists her birinde.

Tabii ki, çekirdeğinizi yeniden derleme ve daha büyük bir değer belirleme olasılığı da var MAX_ARG_PAGES. Ama bir çekirdeği yeniden derlemek, bu cevapta açıklamak istediğimden daha fazla iş.


Bunun neden aşağı oy verildiği hakkında hiçbir fikrim yok. Bunun neden olduğunu açıklayan tek cevap bu. Belki xargs'ı optimizasyon olarak kullanmanızı önermediğiniz için?
chris

xargs çözümüne ekledim, ama hala aşağılarımın ayrıntılarımda açıkça yanlış bir şey olduğundan endişeleniyorum ve kimse bana ne olduğunu söylemek istemiyor. :(
goldPseudo

xargssonuçta ortaya çıkan komut çağrısı sayısı çok daha az olduğu için çok daha verimli görünüyor. Benim durumumda, 6-12 kat daha iyi performans görüyorum, argso zaman -execartan sayıda dosya ile çözüm kullanırken verimlilik artıyor.
Jan Vlcinsky

3

Bunun nedeni, joker karakter ifadenizin ( *.jpg) genişletildiğinde komut satırı bağımsız değişken uzunluğu sınırını aşmasıdır (muhtemelen altında çok sayıda .jpg dosyanız olduğu için /home/ftpuser/public_html/ftparea).

Bu sınırlamayı aşmanın findveya gibi birkaç yolu vardır xargs. Bunun nasıl yapılacağı hakkında daha fazla bilgi için bu makaleye göz atın .


Konuyla ilgili iyi harici kaynak için +1.
viam0Zah

3

GoldPseudo'nun yorumladığı gibi, doğduğunuz bir sürece kaç argüman iletebileceğinize dair bir sınır vardır. Bu parametrenin iyi bir açıklaması için cevabına bakınız.

Süreci çok fazla argüman iletmeyerek veya geçtiğiniz argüman sayısını azaltarak sorunu önleyebilirsiniz.

Kabuktaki bir for döngüsü, find ve ls, grep ve while döngüsü bu durumda aynı şeyi yapar -

for file in /path/to/directory/*.jpg ; 
do
  rm "$file"
done

ve

find /path/to/directory/ -name '*.jpg' -exec rm  {} \;

ve

ls /path/to/directory/ | 
  grep "\.jpg$" | 
  while
    read file
  do
    rm "$file"
  done

tüm dizini (kabuk kendisi, find ve ls) okuyan bir program ve aslında yürütme başına bir bağımsız değişken alır ve tüm komut listesi üzerinden yinelenen farklı bir program var .

Şimdi, bu yavaş olacaktır çünkü rm'nin * .jpg modeliyle eşleşen her dosya için çatallanması ve yürütülmesi gerekir.

Xargs devreye giriyor. xargs standart girdi alır ve her N (freebsd için varsayılan 5000'dir) satırları için N bağımsız değişkeni olan bir program oluşturur. xargs yukarıdaki döngülerin bir optimizasyonudur, çünkü komut satırından bağımsız değişkenleri okuyan tüm dosya kümesini yinelemek için yalnızca 1 / N programlarını çatallamanız gerekir.



1

'*' Glob çok fazla dosya adına genişliyor. Bunun yerine find / home / ftpuser / public_html -name '* .jpg' kullanın.


Bul ve yankı * aynı çıktıyla sonuçlanır - buradaki anahtar, xargs'ı sadece 1 milyar komut satırı argümanının tamamını kabuğun çatallamaya çalıştığı komuta iletmektir.
chris

echo * çok fazla dosya varsa başarısız olur, ancak bulma başarılı olur. Ayrıca, find ile -exec'i + ile kullanmak xargs kullanmaya eşdeğerdir. (Hepsi destek + bulamazlar)
William Pursell

1

Kullanma +seçeneği find -execölçüde çalışmasını hızlandırır.

find  /home/ftpuser/public_html/ftparea/ -name "*jpg" -exec cp -uf -t /your/destination "{}" +

+Seçenek gerektirir {}kullanarak bunu son argüman olarak -t /your/destination(veya --target-directory=/your/destinationhiç) seçeneğini cpişe yapar.

Gönderen man find:

-exec komutu {} +

          This  variant  of the -exec action runs the specified command on  
          the selected files, but the command line is built  by  appending  
          each  selected file name at the end; the total number of invoca  
          tions of the command will  be  much  less  than  the  number  of  
          matched  files.   The command line is built in much the same way  
          that xargs builds its command lines.  Only one instance of  ‘{}’  
          is  allowed  within the command.  The command is executed in the  
          starting directory.

Düzenle : cp'ye yeniden düzenlenmiş argümanlar


Buluyorum: `` exex '' / home / ftpuser1 / public_html / ftparea / -name '* jpg' -exec cp -uf "{}" / home / ftpuser2 / public_html / ftparea / +
icelizard

cpBu hatayı düzeltmek için argümanları yeniden düzenledim .
sonraki duyuruya kadar duraklatıldı.

1

Bu *.jpgdizinde hepsini bir kerede komut satırına koymak için çok fazla dosyanız var gibi görünüyor . Deneyebilirsiniz:

find /home/ftpuser/public_html/ftparea1 -name '*.jpg' | xargs -I {} cp -uf {} /home/ftpuser/public_html/ftparea2/

Anahtarın sisteminiz için doğru man xargsolup olmadığını görmek için uygulamanızı kontrol etmeniz gerekebilir -I.

Aslında, bu dosyaları zaten bulundukları konuma kopyalamak istiyor musunuz?


özür dileriz bu iki farklı dizin ftpuser1 ve ftpuser2 olmalıdır
icelizard

Sadece denedim: ls /home/ftpuser1/public_html/ftparea/*.jpg | xargs -I {} cp -uf {} / home / ftpuser2 / public_html / ftparea / Hala -bash: / bin / ls: Bağımsız değişken listesi çok uzun
icelizard

Oh, oldukça haklısın, elbette lsaynı problemi yaşayacak! Ben değişmeyeceğim find.
Greg Hewgill

0

Klasöre git

cd /home/ftpuser1/public_html/

ve aşağıdakileri yürütün:

cp -R ftparea/ /home/ftpuser2/public_html/

Bu şekilde 'ftparea' klasöründe alt klasörler varsa, yalnızca '* .jpg' dosyalarını ondan istiyorsanız olumsuz bir etki olabilir, ancak herhangi bir alt klasör yoksa, bu yaklaşım kesinlikle daha hızlı olacaktır. find ve xargs kullanma

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.