Xargs ne zaman gerekli?


134

xargsKomut beni hep karıştırır. Bunun için genel bir kural var mı?

Aşağıdaki iki örneği ele alalım:

$ \ls | grep Cases | less

'Cases' ile eşleşen dosyaları yazdırıyor, ancak touchgerektirecek komutu değiştirmek xargs:

$ \ls | grep Cases | touch
touch: missing file operand
Try `touch --help' for more information.

$ \ls | grep Cases | xargs touch

Yanıtlar:


143

Fark, hedef programın hangi verileri kabul ettiğidir.

Sadece bir boru kullanırsanız, STDIN'den (standart giriş akışı) bir seferde bir satır boyunca sıralayabileceği ham veri yığını olarak veri alır. Ancak bazı programlar komutlarını standart olarak kabul etmiyorlar, komutun argümanlarında yazılmayı bekliyorlar. Örneğin touchşöyle komut satırında bir parametre olarak bir dosya adını alır: touch file1.txt.

Eğer dosya adlarını çıktılar bir program varsa dışarı standardı ve bunları kullanmak istediğiniz argümanları olarak için touch, kullanmak zorunda xargsSTDIN akışı verilerini okur ve komuta boşlukla ayrılmış argümanlar içine her satırı dönüştüren hangi.

Bu iki şey eşdeğerdir:

# touch file1.txt
# echo file1.txt | xargs touch

Ne xargsyaptığını ve neden gerekli olduğunu tam olarak bilmiyorsanız kullanmayın . Bu genellikle işi xargsdönüştürmek için kullanmaktan daha iyi bir yol olması durumunda geçerlidir . Dönüşüm süreci ayrıca kaçma ve kelime genişleme vb. Gibi potansiyel tuzaklarla doludur.


2
Uyarı bana küçük bir ip hissediyor. Bir komut satırına ( xargsve $(...)) akış vermek için kullanılan iki yaygın seçenek arasında , xargs komut değiştirmeden çok daha güvenlidir. Ve meşru bir dosya ismine, içinde yeni bir çizgiyle geldiğimi hatırlayamıyorum. Kaçış ve kelime genişletme tuzaklar, xargs ile değil, komut değiştirme ile ilgili sorunları değil midir?
saat

6
@ camh: Her ikisi ile de potansiyel tuzaklar. Kabukta, boşluklarda, sekmelerde ve yeni satırlarda bölünmüş dosya isimleri konusunda endişelenmeniz gerekir. Xargs'ta sadece yeni hatlar için endişelenmen gerekiyor. Xargs'da, çıktınız doğru biçimlendirilmişse, kelimeleri / dosya adlarını NUL karakterine bölerek ( xargs -0) ile birlikte kullanabilirsiniz find -print0.
Ken Bloom,

Does xargsboşlukla ayrılmış args ile kabuk aracılığıyla programı arayabilir veya aslında içten argüman listesi oluşturmak gelmez (örn. Kullanılmak üzere execv/ ' execp)?
55'te

1
Dahili olarak inşa eder ve execvp kullanır, bu yüzden güvenlidir. Ayrıca, GNU xargs (Linux'ta ve diğer bir kaçında olduğu gibi) -d \n, BSD xargs (OSX et al) bu seçeneği desteklemiyor gibi görünmesine rağmen sınırlayıcı olarak newline'ı belirtmenize izin verir .
kabarık

72

Daha önce verilmiş olan cevapları genişletmek için xargsgünümüzün çok çekirdekli ve dağınık bilgisayar ortamında giderek daha önemli hale gelen havalı bir şey yapabilir: süreçleri paralel yapabilir.

Örneğin:

$ find . -type f -name '*.wav' -print0 |xargs -0 -P 3 -n 1 flac -V8

Aynı anda üç işlemi kullanarak * .wav => * .flac kodunu verecektir -P 3.


Vay. Bunu bir hafta önce 50GiB WAV'larla aynı şeyi (OGG kullanmak hariç) yaptığım zaman bilmeliydim. :)
Alois Mahdal

neden bulan -exec parametresini kullanmıyorsun?
Evgeny

3
@Evgeny -execParametre, paralel işlem işlerini yürütmez .
amfetamachine

Yapacağı -0argümanınxargsNULL karakteri giriş öğesi sınırlayıcısı olarak kabul etmesine dikkat etmek iyidir. find -print0NULL ile ayrılmış öğeler çıktılar. Bu, boşluk, tırnak veya başka özel karakterler içerebilen dosya isimleri için harika bir uygulamadır.
Dan Dascalescu

24

xargs özellikle stdin'deki bir filepat listeniz varsa ve onlarla bir şeyler yapmak istediğinizde kullanışlıdır. Örneğin:

$ git ls-files "*.tex" | xargs -n 1 sed -i "s/color/colour/g"

Bu adımı adım adım inceleyelim:

$ git ls-files "*.tex"
tex/ch1/intro.tex
tex/ch1/motivation.tex
....

Başka bir deyişle, girişimiz bir şey yapmak istediğimiz yolların bir listesidir.

Xargs'ın bu yollarla ne yaptığını bulmak için echo, komutunuzdan önce şöyle eklemek için güzel bir numara ekleyin :

$ git ls-files "*.tex" | xargs -n 1 echo sed -i "s/color/colour/g"
sed -i "s/color/colour/g" tex/ch1/intro.tex
sed -i "s/color/colour/g" tex/ch1/motivation.tex
....

-n 1Argüman Xargs kendine ait bir komuta içine her satırı açmak yapacaktır. sed -i "s/color/colour/g"Komut tüm oluşumları yerini alacak colorolan colourbelirtilen dosya için.

Bunun yalnızca yollarınızda boşluk yoksa işe yarayacağını unutmayın. Bunu yaparsanız, -0bayrağı geçerek boş uçlu yolları xargs'a girdi olarak kullanmalısınız . Örnek bir kullanım:

$ git ls-files -z "*.tex" | xargs -0 -n 1 sed -i "s/color/colour/g"

Yukarıda tarif ettiğimizle aynı olan, ancak yollardan birinin içinde bir boşluk varsa da çalışır.

Bu, dosya ismini findveya gibi çıktı olarak veren herhangi bir komutla çalışır locate. Çok sayıda dosya içeren bir git deposunda kullanıyorsanız, git grep -lbunun yerine bununla kullanmak daha verimli olabilir git ls-files:

$ git grep -l "color" "*.tex" | xargs -n 1 sed -i "s/color/colour/g"

git grep -l "color" "*.tex"Komut ifadesini "renk" içeren "* .tex" dosyaların bir listesini verecektir.


1
Doğru, ancak bu öğrendim eğer gerektiğini de öğrenmek Neden Bul'un çıkışı kötü uygulama üzerinde döngü nedir?
Joker

6

İlk argümanınız farkı çok iyi gösteriyor.

\ls | grep Cases | lesslsve tarafından üretilen dosya adları listesine göz atmanızı sağlar grep. Onların dosya adı olması önemli değil, sadece birer metin.

\ls | grep Cases | xargs lessKomutun ilk kısmı tarafından isimleri üretilen dosyalara göz atmanızı sağlar. xargsgiriş ve komut satırında bir komut olarak dosya adlarının bir listesini alır ve dosya adları ile komutu çalıştırır onun komut satırında.

Kullanarak değerlendirirken xargsile, boşluk ayrılmış:, tuhaf bir şekilde biçimlendirilmiş girdi beklediğini unutmayın \, 've "(çünkü, alışılmadık bir şekilde alıntı kullanılan \değil özel iç tırnak olduğunu). Yalnızca xargsdosya adlarınız boşluk içermiyorsa veya kullanın \'".


@Gilles: Alanlar sorununu çözme seçeneğine xargssahiptir -0, --null(büyük olasılıkla sizden öğrendim :), bu nedenle seçeneksiz bir çağrıya atıfta bulunduğunuzu varsayıyorum xarg, ancak alıntılara başvurduğunuzda şaşırdım. Bununla ilgili bir bağlantınız veya bir örneğiniz var mı? .. (ps. | xargs lesskullanışlı bir "numaradır" +1 .. teşekkürler ..
Peter.O

4

Örnekte kullanmak gerekmez xargsçünkü hiç findtam ve güvenli bir şekilde size ne yapmak istediğinizi yapacağız.

Tam olarak kullanmak istediğin findşey:

find -maxdepth 1 -name '*Cases*' -exec touch {} +

Bu örnekte -maxdepth 1, yalnızca geçerli dizinde arama yapmak anlamına gelir, herhangi bir alt dizine girmeyin; Varsayılan olarak find, maxdepth ile sınırlandırmadıkça tüm alt dizinlere bakacak (bu genellikle istediğiniz şeydir). {}Bununla değiştirilir ve alacak dosyanın adıdır +iki uç emir-komuta işaretlerden biri diğer varlıktır ;. Aralarındaki fark ;, komutların her seferinde bir defada tek tek +çalıştırılması, komutların ise aynı anda tüm dosyalarda çalıştırılmasıdır. Bununla birlikte, kabuğunuzun muhtemelen ;kendisini yorumlamaya çalışacağını , bu nedenle ya \;da ile kaçmak zorunda kalacağınızı unutmayın ';'. Evet, findbunun gibi bir takım küçük sıkıntılara sahiptir, ancak gücü bunun için telafi etmekten daha fazladır.

Her ikisi de findve xargsilk başta öğrenmek zor. Öğrenmenize yardımcı olmak için, çalıştırmak üzere olduğu komutu size gösterecek olan ya da seçeneği xargskullanmayı deneyin ve çalıştırmak isteyip istemediğinizi sorar.-p--interactive

Benzer şekilde , komutu çalıştırmak isteyip istemediğinizi sormak için yerine findkullanabilirsiniz .-ok-exec

findİstediğiniz her şeyi yapamayacağınız zamanlar vardır ve xargsiçeri girdiği yer burasıdır . -execKomut yalnızca {}görünen bir örneği kabul eder , böylece bir hata find -type f -exec cp {} {}.bak \;alırsanız, bunun yerine :find -type f -print0 | xargs -0 -l1 -IX cp X X.bak

Sen hakkında daha fazla bilgi edinebilirsiniz Çalıştır Komutları içinde GNU Findutils kılavuzda .

Ayrıca, findgüvenli bir şekilde istediğinizi yaptığınızdan da bahsettim, çünkü dosyalarla uğraşırken veya yerine boş bir karakterle sonlandırılan girdi öğelerini üreten bir öğeyi birlikte xargskullanmadığınız sürece sorunlara neden olacak diğer karakterlerle karşılaşacaksınız. boşluk.-0--null



@Wildcard dosya isimleri boşluklu veya karakterli ya da karakterli 'ya "da problemli olabilir, oysa ki findbu davaları problemsizce halledecektir.
aculich

Evet biliyorum. Bağlantılı soruya cevabımı gör . Muhtemelen bu soruyu yukarıdaki yorumdaki bir ifadeye göre yeniden yazmalı ya da önüne "Soruyu görün ..." ifadesini eklemeliydim. : D
Joker

1

xargs(birlikte find, sort, du, uniq, perlve birkaç diğerleri) "STDIN bir boş (0x00) byte ile ayrılmış dosyaların bir listesi vardır" demek için bir komut satırı anahtarını kabul eder. Bu, dosya adlarında boşluk ve bunlarda diğer komik karakterlerin kullanılmasını kolaylaştırır. Dosya adları NUL içermiyor.


2
Bence "dosya isimleri boş olamaz " demek istiyorsun .
amfetamachine
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.