Bana öyle geliyor ki, bu sayfadaki mevcut cevaplar yanlış (doğru olarak işaretlenmiş olanlar dahil). Bu, sorunun belirsiz bir şekilde ifade edildiği gerçeğinden kaynaklanmaktadır.
Özet: Komutun tamamını (yeni satır olmadan) komuta tek bir argüman olarak ileterek "verilen her girdi satırı için tam olarak bir kez" komutunu yürütmek istiyorsanız , bu UNIX uyumlu en iyi yoldur:
... | tr '\n' '\0' | xargs -0 -n1 ...
GNU xargs
, ortadan kaldırmanıza izin veren yararlı uzantılara sahip olabilir veya olmayabilir tr
, ancak OS X ve diğer UNIX sistemlerinde mevcut değildir.
Şimdi uzun bir açıklama için…
Xargs kullanırken dikkate alınması gereken iki sorun vardır:
- girdiyi "argümanlara" nasıl böler; ve
- child komutunu bir seferde kaç argümanın geçeceğini.
Xargs'ın davranışını test etmek için, kaç kez yürütüldüğünü ve kaç argümanla olduğunu gösteren bir yardımcı programa ihtiyacımız var. Bunu yapmak için standart bir yardımcı program olup olmadığını bilmiyorum, ama bash kolayca kodlayabilirsiniz:
#!/bin/bash
echo -n "-> "; for a in "$@"; do echo -n "\"$a\" "; done; echo
show
Geçerli dizininizdeki gibi kaydettiğinizi ve çalıştırılabilir hale getirdiğinizi varsayarsak , şöyle çalışır:
$ ./show one two 'three and four'
-> "one" "two" "three and four"
Şimdi, eğer asıl soru gerçekten 2. nokta ile ilgili ise (sanırım, birkaç kez okuduktan sonra) ve bu şekilde okunmalıdır (kalın değişiklikler):
Xargs komutunun verilen her bir giriş argümanı için tam olarak bir kez çalışmasını nasıl sağlayabilirim ? Varsayılan davranışı, girdiyi bağımsız değişkenlere yığınlamak ve komutu her örneğe birden çok bağımsız değişken ileterek mümkün olduğunca az yürütmektir .
o zaman cevap -n 1
.
Girdiyi boşluk içine ayıran ve komutu mümkün olduğunca az kez çağıran xargs'ın varsayılan davranışını karşılaştıralım:
$ echo one two 'three and four' | xargs ./show
-> "one" "two" "three" "and" "four"
ve davranışları -n 1
:
$ echo one two 'three and four' | xargs -n 1 ./show
-> "one"
-> "two"
-> "three"
-> "and"
-> "four"
Öte yandan, asıl soru nokta 1 ile ilgiliyse. Giriş bölme ve bu şekilde okunacaksa (buraya gelen birçok kişi durumun böyle olduğunu düşünüyor veya iki konuyu karıştırıyor gibi görünüyor):
Nasıl Xargs komutunu çalıştırmak yapabilirsiniz ile tam bir argüman verilen girişin her satırı için? Varsayılan davranışı, boşluk çevresindeki çizgileri yığınlamaktır .
o zaman cevap daha incedir.
Biri bunun -L 1
yardımcı olabileceğini düşünür , ancak argüman ayrışmasını değiştirmediği ortaya çıkıyor. Komutu, her bir girdi satırı için yalnızca bir kez, o girdi satırında olduğu kadar çok argümanla yürütür:
$ echo $'one\ntwo\nthree and four' | xargs -L 1 ./show
-> "one"
-> "two"
-> "three" "and" "four"
Sadece bu değil, bir satır boşlukla bitiyorsa, bir sonrakine eklenir:
$ echo $'one \ntwo\nthree and four' | xargs -L 1 ./show
-> "one" "two"
-> "three" "and" "four"
Açıkçası, -L
xargs'ın girdiyi bağımsız değişkenlere ayırma biçimini değiştirmekle ilgili değildir.
Bunu çapraz platform biçiminde (GNU uzantıları hariç) yapan tek argüman -0
, girdiyi NUL baytlarına böler.
O zaman, bu sadece yeni satırları NUL'a çeviri yardımı ile yapar tr
:
$ echo $'one \ntwo\nthree and four' | tr '\n' '\0' | xargs -0 ./show
-> "one " "two" "three and four"
Şimdi argüman ayrıştırma, sondaki boşluk dahil olmak üzere iyi görünüyor.
Son olarak, bu tekniği birleştirirseniz -n 1
, giriş satırınız başına tam olarak bir komut yürütme elde edersiniz, hangi girdiniz varsa, orijinal soruya bakmanın başka bir yolu olabilir (muhtemelen en sezgisel, başlık verilir):
$ echo $'one \ntwo\nthree and four' | tr '\n' '\0' | xargs -0 -n1 ./show
-> "one "
-> "two"
-> "three and four"
find /path -type f -delete
daha da verimli olurdu :)