Xargs öğesinin boşluk içeren dosya adlarını işlemesini sağlama


253
$ ls *mp3 | xargs mplayer  

Playing Lemon.  
File not found: 'Lemon'  
Playing Tree.mp3.  
File not found: 'Tree.mp3'  

Exiting... (End of file)  

Komutum başarısız çünkü "Lemon Tree.mp3" dosyası boşluk içeriyor ve bu nedenle xargs iki dosya olduğunu düşünüyor. Find + xargs dosyasının dosya adları ile çalışmasını sağlayabilir miyim?


Bunun yerine ls |grep mp3 |sed -n "7p"sadece kullanabilirsiniz echo "Lemon Tree.mp3".
Micha Wiedenmann


Bu soru ayrıca cevaplanmıştır. Stackoverflow.com/a/33528111/94687
imz - Ivan Zakharyaschev

Yanıtlar:


256

xargsKomut sınırlayıcı olarak boşluk karakterleri (Sekmeleri, boşlukları yeni hat) sürer. Bunu yalnızca aşağıdaki gibi yeni satır karakterleri ('\ n') için daraltabilirsiniz -d:

ls *.mp3 | xargs -d '\n' mplayer

Yalnızca GNU xargs ile çalışır. BSD sistemleri için şu -0seçeneği kullanın :

ls *.mp3 | xargs -0 mplayer

Bu yöntem daha basittir ve GNU xargs ile de çalışır.


6
Genel kullanım için en iyi cevap! Bu, önceki komutunuz "bul" olmasa bile çalışır
nexayq

28
Ne yazık ki, bu seçenek OS X'te mevcut değildir.
Thomas Tempelmann

25
@Thomas OS X için bayrak şu -Exargs -E '\n'

30
OS X'te, -E '\ n' nin benim için bir etkisi olmadı, ne de kayıt ayırıcıyı değil, eofstr'i değiştirdiğinden beklemem. Ancak, önceki komut 'find' olmasa bile, -0 bayrağını girişimde find -print0 bayrağının etkisini simüle ederek bir çözüm olarak kullanabildim, örneğin: ls * mp3 | tr '\ n' '\ 0' | xargs -0 mplayer
biomiker

10
OS X için, size "gxargs" komutunu veren "findutils yüklemek demlemek" olabilir yapar -d anahtarını var.
Tom De Leu

214

Xargs yardımcı programı, standart girdiden boşluk, sekme, satırsonu ve dosya sonu ayrılmış dizeleri okur ve dizgilerle yardımcı programı bağımsız değişken olarak yürütür.

Alanı sınırlayıcı olarak kullanmaktan kaçınmak istersiniz. Bu, xargs için sınırlayıcı değiştirilerek yapılabilir. El kitabına göre:

 -0      Change xargs to expect NUL (``\0'') characters as separators,
         instead of spaces and newlines.  This is expected to be used in
         concert with the -print0 function in find(1).

Gibi:

 find . -name "*.mp3" -print0 | xargs -0 mplayer

Yedinci mp3 çalma sorusunu cevaplamak için; koşmak daha basit

 mplayer "$(ls *.mp3 | sed -n 7p)"

10
Bu GNU findve GNU kullanıyor xargs; bu programların tüm sürümleri bu seçenekleri desteklemez (ancak yapılması gereken bir durum vardır).
Jonathan Leffler

1
@JonathanLeffler s / GNU / FreeBSD / g; POSIX, maalesef metin dosyalarındaki NUL karakterlerinden korkuyor ve henüz yeterli terapiye sahip değil :-) Aslında tavsiyem taşınabilir olmayan seçeneklere başvuruyor.
Jens

6
Ve Mac OS X (bir BSD türevi) findile -print0ve xargsile birlikte -0. AFAIK, HP-UX, AIX ve Solaris bunu yapmaz (ancak düzeltilmeye devam ediyorum: HP-UX 11i yapmadı; Solaris 10 yapmadı; AIX 5.x yapmadı; ama mevcut sürümler değiller ). Bu değişikliğe zor olmaz sedbiten çizilen kullanmak, örneğin, '\0'yerine '\n've POSIX 2008 getdelim()kolay yönetmek için yapar.
Jonathan Leffler

2
Liste dosyalarını içeren dosya yollarıyla kullanım için +1 + 1 hile: cat $ file_paths_list_file | perl -ne 's | \ n | \ 000 | g; yazdır' | xargs -0 zip $ zip_package
Yordan Georgiev

2
Yeni satırları NUL ile değiştirmek için iyi bir fikir - Bunu GNU bulması, GNU xargs veya perl içermeyen gömülü bir sistemde yapmak zorunda kaldım - ancak tr komutu aynı şeyi yapmak için kaldırabilir: cat $ file_paths_list_file | tr '\ n' '\ 0' | xargs -0 du -hms
joensson

28

Deneyin

find . -name \*.mp3 -print0 | xargs -0 mplayer

onun yerine

ls | grep mp3 

16

MacOS'ta xargs -d seçeneğine sahip olmadığından, bu çözüm bunun yerine -0 kullanır.

Satır başına bir dosya çıktısı almak için ls alın, sonra satırları boş değerlere çevirin ve xargs'a sınırlayıcı olarak boş değer kullanmasını söyleyin:

ls -1 *mp3 | tr "\n" "\0" | xargs -0 mplayer


8
find . -name 'Lemon*.mp3' -print0 | xargs 0 -i mplayer '{}' 

Bu benim durumumda boşluklu farklı dosyaları silmek için yardımcı oldu. Mplayer ile de çalışmalıdır. Gerekli numara tırnak. (Linux Xubuntu 14.04'te test edildi .)


7

Dick.Guertin'in cevabı [1], bir dosya adındaki boşluklardan kaçabileceğini, burada önerilen diğer çözümlere (beyaz boşluk yerine ayırıcı olarak boş bir karakter kullanmak gibi) değerli bir alternatif olduğunu öne sürdü. Ama daha basit olabilir - gerçekten benzersiz bir karaktere ihtiyacınız yoktur. Kaçan boşlukları doğrudan sed eklemeniz yeterlidir:

ls | grep ' ' | sed 's| |\\ |g' | xargs ...

Eğer Dahası, grep gereklidir yalnızca adlarında boşluk içeren dosyaları istiyoruz. Daha genel olarak (örneğin, bazıları boşluklu olan, bazıları olmayan bir grup dosyayı işlerken) sadece grep'i atlayın:

ls | sed 's| |\\ |g' | xargs ...

Daha sonra, elbette, dosya adının boşluklardan başka bir boşluk olabilir (örneğin, bir sekme):

ls | sed -r 's|[[:blank:]]|\\\1|g' | xargs ...

Bu, GNU sed veya bsd sed'in son sürümleri (örn., FreeBSD 8'den önce "-E" seçeneğini başlangıçta yazan ve uyumluluk için hem -r & -E'yi destekleyen -r'yi (genişletilmiş normal ifade) destekleyen bir sediniz olduğunu varsayar. en az FreeBSD 11 yoluyla). Aksi takdirde, normal regex karakter sınıfı köşeli ayraç ifadesini kullanabilir ve []ayırıcılara boşluk ve sekme karakterlerini manuel olarak girebilirsiniz .

[1] Bu, belki de bir cevap için bir yorum veya düzenleme olarak daha uygundur, ancak şu anda yorum yapmak için yeterli itibarım yok ve sadece düzenlemeler önerebilirim. Yukarıdaki son formlar (grep olmadan) Dick.Guertin'in orijinal cevabının davranışını değiştirdiğinden, doğrudan bir düzenleme belki de uygun değildir.


1
çıktılarını göz önünde bulundurmadan komut dosyaları bu çılgın unix çocuklar, o kim
andrew lorien

4

ls | grep mp3 | sed -n "7p" | xargs -i mplayer {}

Yukarıdaki komutta, her dosya için yeniden xargsçağrı yapacağını unutmayın mplayer. Bu istenmeyen bir durum olabilir mplayer, ancak diğer hedefler için uygun olabilir.


1
Mevcut cevaplara yararlı bir ek, ancak bunun mplayerher dosya için yeniden çağrılmasına neden olacağını belirtmek gerekir. Örneğin şunu denemeniz önemlidir ... | xargs -I{} mplayer -shuffle {}: bu tamamen kararlı bir sırayla oynayacaktır -shuffle.

1
Muhtemelen amaç bu değildir. xargsçoğunlukla dosya adlarının bir listesini kabul eden komutlarla kullanılır (kolay örnek rm:) ve her çağrışmaya sığabilecek kadar çok dosya adı aktarmaya çalışır, yalnızca gerekirse birden çok çağrmaya bölünür. Her bir çağrının göründüğü bir komutu kullandığınızda echo(varsayılan) farkı görebilirsiniz: örneğin (varsayılan): seq 0 100000 | xargs0'dan 23695'e (platforma özgü, ancak sistemime ne olur) tüm satırları ilk satırda 45539'a yazdırır Ve doğru, çoğu komut için önemli değil.

4

MacOS 10.12.x'te (Sierra), dosya adlarında veya alt dizinlerde boşluk varsa, aşağıdakileri kullanabilirsiniz:

find . -name '*.swift' -exec echo '"{}"' \; |xargs wc -l

2

Bu, (a) örneğin Limonlar yerine 7 numarasına ne kadar bağlı olduğunuza ve (b) dosya adlarınızdan herhangi birinin yeni satır içerip içermediğine (ve varsa yeniden adlandırmak isteyip istemediğinize) bağlıdır.

Bununla başa çıkmanın birçok yolu vardır, ancak bazıları:

mplayer Lemon*.mp3

find . -name 'Lemon*.mp3' -exec mplayer {} ';'

i=0
for mp3 in *.mp3
do
    i=$((i+1))
    [ $i = 7 ] && mplayer "$mp3"
done

for mp3 in *.mp3
do
    case "$mp3" in
    (Lemon*) mplayer "$mp3";;
    esac
done

i=0
find . -name *.mp3 |
while read mp3
do
    i=$((i+1))
    [ $i = 7 ] && mplayer "$mp3"
done

readDosya adları yeni satır içeriyorsa döngü çalışmaz; diğerleri isimlerdeki yeni satırlarla bile doğru çalışır (boşluklar olsun). Param için, yeni satır içeren dosya adlarınız varsa, dosyayı yeni satır olmadan yeniden adlandırmalısınız. Dosya adının etrafındaki çift tırnak işaretlerinin kullanılması, döngülerin düzgün çalışmasının anahtarıdır.

GNU findve GNU'nuz xargs(veya FreeBSD (* BSD?) Veya Mac OS X) varsa, -print0ve -0seçeneklerini aşağıdaki gibi kullanabilirsiniz :

find . -name 'Lemon*.mp3' -print0 | xargs -0 mplayer

Bu, adın içeriğinden bağımsız olarak çalışır (dosya adında görünmeyen yalnızca iki karakter eğik çizgi ve NUL şeklindedir ve eğik çizgi bir dosya yolunda sorunlara neden olmaz, bu nedenle ad sınırlayıcı olarak NUL kullanılması her şeyi kapsar). Ancak, ilk 6 girişi filtrelemeniz gerekiyorsa, newline yerine NUL ile biten 'satırları' işleyen bir programa ihtiyacınız var ...

Birincisi, eldeki özel durum için açık ara en basit olanıdır; ancak, henüz listelemediğiniz diğer senaryolarınızı kapsamak genelleşmeyebilir.


2

Ben cevap vermeyeceğim biliyoruz xargsdoğrudan soru ama onun bahsetmemiz find'ın -execseçeneği.

Aşağıdaki dosya sistemi göz önüne alındığında:

[root@localhost bokeh]# tree --charset assci bands
bands
|-- Dream\ Theater
|-- King's\ X
|-- Megadeth
`-- Rush

0 directories, 4 files

Find komutu Dream Theatre ve King's X'teki alanı idare etmek için yapılabilir. Yani, grep kullanarak her bandın davulcularını bulmak için:

[root@localhost]# find bands/ -type f -exec grep Drums {} +
bands/Dream Theater:Drums:Mike Mangini
bands/Rush:Drums: Neil Peart
bands/King's X:Drums:Jerry Gaskill
bands/Megadeth:Drums:Dirk Verbeuren

Gelen -execseçeneği {}yolu da dahil olmak üzere dosya kısaltmasıdır. Kaçmak veya tırnak içine almak zorunda olmadığını unutmayın.

-exec'Nin sonlandırıcıları ( +ve \;) arasındaki fark +, bir komut satırına alabileceği kadar çok dosya adı gruplamasıdır. Oysa \;her dosya adı için komutu yürütür.

Böylece, find bands/ -type f -exec grep Drums {} +sonuç:

grep Drums "bands/Dream Theater" "bands/Rush" "bands/King's X" "bands/Megadeth"

ve find bands/ -type f -exec grep Drums {} \;şunlarla sonuçlanır:

grep Drums "bands/Dream Theater"
grep Drums "bands/Rush"
grep Drums "bands/King's X"
grep Drums "bands/Megadeth"

Bu durumda grep, dosya adını yazdırmanın ya da yazdırmamanın yan etkisi vardır.

[root@localhost bokeh]# find bands/ -type f -exec grep Drums {} \;
Drums:Mike Mangini
Drums: Neil Peart
Drums:Jerry Gaskill
Drums:Dirk Verbeuren

[root@localhost bokeh]# find bands/ -type f -exec grep Drums {} +
bands/Dream Theater:Drums:Mike Mangini
bands/Rush:Drums: Neil Peart
bands/King's X:Drums:Jerry Gaskill
bands/Megadeth:Drums:Dirk Verbeuren

Tabii ki, grep'seçenekleri -hve -Hnasıl grepadlandırılır olursa olsun dosya adının yazdırılıp yazdırılmayacağını kontrol eder .


xargs

xargs ayrıca man dosyalarının komut satırında nasıl olduğunu da kontrol edebilir.

xargsvarsayılan olarak tüm bağımsız değişkenleri tek bir satıra gruplar. Aynı şeyi yapmak için -exec \;kullanıyor mu xargs -l. -tSeçeneğin xargskomutu çalıştırmadan önce yazdırmayı söylediğini unutmayın .

[root@localhost bokeh]# find ./bands -type f  | xargs -d '\n' -l -t grep Drums
grep Drums ./bands/Dream Theater 
Drums:Mike Mangini
grep Drums ./bands/Rush 
Drums: Neil Peart
grep Drums ./bands/King's X 
Drums:Jerry Gaskill
grep Drums ./bands/Megadeth 
Drums:Dirk Verbeuren

-lSeçeneğin xargs'a her dosya adı için grep yürütmesini söylediğini görün .

Varsayılana karşı (yani -lseçenek yok ):

[root@localhost bokeh]# find ./bands -type f  | xargs -d '\n'  -t grep Drums
grep Drums ./bands/Dream Theater ./bands/Rush ./bands/King's X ./bands/Megadeth 
./bands/Dream Theater:Drums:Mike Mangini
./bands/Rush:Drums: Neil Peart
./bands/King's X:Drums:Jerry Gaskill
./bands/Megadeth:Drums:Dirk Verbeuren

xargskomut satırında kaç dosya olabileceği konusunda daha iyi denetime sahiptir. Seçeneğe -lkomut başına maksimum dosya sayısı verin .

[root@localhost bokeh]# find ./bands -type f  | xargs -d '\n'  -l2 -t grep Drums
grep Drums ./bands/Dream Theater ./bands/Rush 
./bands/Dream Theater:Drums:Mike Mangini
./bands/Rush:Drums: Neil Peart
grep Drums ./bands/King's X ./bands/Megadeth 
./bands/King's X:Drums:Jerry Gaskill
./bands/Megadeth:Drums:Dirk Verbeuren
[root@localhost bokeh]# 

Bunun grepyüzünden iki dosya adıyla yürütüldüğüne bakın -l2.


1

Bu yazının özel başlığı göz önüne alındığında, benim önerim:

ls | grep ' ' | tr ' ' '<' | sed 's|<|\\ |g'

Fikir, boşlukları '<' gibi herhangi bir benzersiz karaktere dönüştürmek ve sonra bunu '\', ters eğik çizgi ve ardından boşluk olarak değiştirmek. Daha sonra, bunu istediğiniz gibi herhangi bir komuta bağlayabilirsiniz:

ls | grep ' ' | tr ' ' '<' | sed 's|<|\\ |g' | xargs -L1 GetFileInfo

Buradaki anahtar 'tr' ve 'sed' komutlarında yatmaktadır; ve '<' dışında '?' gibi herhangi bir karakter kullanabilirsiniz. hatta bir sekme karakteri.


Yoldan sapmanın amacı nedir tr? Neden sadece ls *.mp3 | sed -n '7!b;s/\([[:space:]]\)/\\\1/g;p'?
tripleee

1
Ben "tr" "?" "Bulduk" sed "ihtiyacını ortadan kaldırır. Yalnız "?" karakteri boş değil, ancak bu durumda HERHANGİ BİR tek karakterle eşleşir: boş. Başka bir şey olma olasılığı oldukça küçüktür ve .mp3 ile biten TÜM dosyaları işlemeye çalıştığınız için kabul edilebilirdir: "ls | grep '' | tr '' '?' ' | xargs -L1 GetFileInfo "
Dick Guertin

Ayrıca "sekme" yi aynı anda işleyebilirsiniz: tr '\ t' '??' her ikisini de işler.
Dick Guertin

1

Alternatif çözümler yardımcı olabilir ...

Ayrıca Perl kullanarak satırlarınızın sonuna boş bir karakter ekleyebilir ve ardından -0 xargs'daki seçeneği . Xargs -d '\ n' (onaylı yanıtta) aksine - bu, OS X dahil her yerde çalışır.

Örneğin, boşluklar veya diğer komik karakterler içerebilen MPEG3 dosyalarını özyinelemeli olarak listelemek (yürütmek, taşımak, vb.) - Kullanırım:

find . | grep \.mp3 | perl -ne 'chop; print "$_\0"' | xargs -0  ls

(Not: Filtreleme için, "find's" - name bağımsız değişkenlerine hatırlanması kolay "| grep" sözdizimini tercih ederim.)

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.