Xargs को उन फ़ाइलनाम को हैंडल करें जिनमें रिक्त स्थान हैं


252
$ ls *mp3 | xargs mplayer  

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

Exiting... (End of file)  

मेरा आदेश विफल हो जाता है क्योंकि फ़ाइल "लेमन ट्री. एमपी 3" में रिक्त स्थान हैं और इसलिए xargs को लगता है कि यह दो फाइलें हैं। क्या मैं इस तरह के फ़ाइल नाम के साथ + xargs काम पा सकता हूं?


ls |grep mp3 |sed -n "7p"आप के बजाय बस का उपयोग कर सकते हैं echo "Lemon Tree.mp3"
मीका विडेनमैन


इस सवाल का जवाब stackoverflow.com/a/33528111/94687
imz - Ivan Zakharyaschev

जवाबों:


255

xargsआदेश डिलीमीटर के रूप में सफेद स्थान अक्षर (टैब, रिक्त स्थान, नई लाइनों) लेता है। आप इसे केवल -dइस तरह के विकल्प के साथ नई पंक्ति वर्ण ('\ n') के लिए संकीर्ण कर सकते हैं :

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

यह केवल GNU xargs के साथ काम करता है। बीएसडी सिस्टम के लिए, -0इस तरह के विकल्प का उपयोग करें:

ls *.mp3 | xargs -0 mplayer

यह विधि सरल है और GNU xargs के साथ भी काम करती है।


6
सामान्य उपयोग के लिए सबसे अच्छा जवाब! यह तब भी काम करता है जब आपका पिछला कमांड "नहीं" हो
nexayq

28
दुर्भाग्य से, यह विकल्प ओएस एक्स पर उपलब्ध नहीं है।
थॉमस टेम्पेलमैन

25
@Thomas OS X के लिए, ध्वज है -E, पूर्व:xargs -E '\n'

30
OS X पर, -E '\ n' का मेरे लिए कोई प्रभाव नहीं था, और न ही मैं इसकी अपेक्षा करूंगा क्योंकि यह सबसे अलग और रिकॉर्ड विभाजक को संशोधित करता है। हालाँकि, मैं -0 ध्वज को एक समाधान के रूप में उपयोग करने में सक्षम था, भले ही पिछली कमांड 'इनपुट' न हो, मेरे इनपुट में -प्रिंट0 फ़्लैग के प्रभाव का अनुकरण करके, जैसे: ls * mp3 | tr '\ n' '\ 0' | xargs -0 mplayer
बायोमाइकर

10
OS X के लिए, आप "फाउंड इंस्टॉल स्थापित कर सकते हैं", जो आपको "gxargs" कमांड देता है जिसमें -d स्विच होता है।
टॉम डे लेउ

213

Xargs की उपयोगिता मानक इनपुट से स्पेस, टैब, न्यूलाइन और एंड-ऑफ-द-फ़ाइल सीमांकित स्ट्रिंग्स को पढ़ती है और स्ट्रिंग्स के साथ उपयोगिता को तर्कों के रूप में निष्पादित करती है।

आप एक सीमांकक के रूप में स्थान का उपयोग करने से बचना चाहते हैं। यह xargs के लिए सीमांकक को बदलकर किया जा सकता है। मैनुअल के अनुसार:

 -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).

जैसे कि:

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

सातवें एमपी 3 खेलने के बारे में सवाल का जवाब देने के लिए; इसे चलाना सरल है

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

10
यह GNU findऔर GNU का उपयोग कर रहा है xargs; उन कार्यक्रमों के सभी संस्करण उन विकल्पों का समर्थन नहीं करते हैं (हालांकि ऐसा मामला होना चाहिए जो उन्हें होना चाहिए)।
जोनाथन लेफ़लर

1
@JonathanLeffler s / GNU / FreeBSD / g; POSIX दुखद रूप से पाठ फ़ाइलों में एनयूएल वर्णों से डरता है और अभी तक पर्याप्त चिकित्सा नहीं थी :-) वास्तव में गैर-पोर्टेबल विकल्पों के लिए मेरी सलाह।
जेन्स

6
और मैक ओएस एक्स (एक बीएसडी व्युत्पन्न) के findसाथ -print0और xargsसाथ है -0। AFAIK, HP-UX, AIX और Solaris नहीं है, लेकिन (लेकिन मैं सही होने के लिए खड़ा हूं: HP-UX 11i नहीं; Solaris 10 नहीं; AIX 5.x नहीं; लेकिन वे वर्तमान संस्करण नहीं हैं )। sedउदाहरण के लिए, 'लाइनों' का उपयोग करने के '\0'बजाय अंत में बदलना कठिन नहीं होगा '\n', और POSIX 2008 getdelim()को प्रबंधित करना आसान होगा।
जोनाथन लेफ़लर

2
सूची पथ युक्त फ़ाइल पथों के साथ उपयोग करने के लिए +1 + 1 ट्रिक: cat $ file_paths_list_file | perl -ne 's | \ n | \ 000 | g; प्रिंट' xargs -0 $ zip_package ज़िप
योर्डन जॉर्जियेव

2
एनयूएल के साथ नई कहानियों को बदलने के लिए अच्छा विचार - मुझे यह एक एम्बेडेड सिस्टम पर करना था जिसमें GNU नहीं था और न ही GNU xargs और न ही पर्ल - लेकिन tr कमांड को ऐसा करने के लिए उत्तोलन किया जा सकता है: cat $ file_p_s_list_file | tr '\ n' '\ 0' | xargs -0 du -hms
joensson


16

MacOS पर xargs के पास -d विकल्प नहीं है, इसलिए यह समाधान -0 के बजाय का उपयोग करता है।

प्रति पंक्ति एक फ़ाइल आउटपुट करने के लिए ls प्राप्त करें, फिर newlines को nulls में अनुवाद करें और xargs को यह बताएं कि यह delbiter के रूप में nulls का उपयोग करने के लिए है:

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


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

इससे रिक्त स्थान वाली विभिन्न फ़ाइलों को हटाने में मेरे मामले में मदद मिली। इसे मेप्लर के साथ भी काम करना चाहिए। आवश्यक चाल उद्धरण है। (लिनक्स Xubuntu 14.04 पर परीक्षण किया गया ।)


7

डिक.गर्टिन के उत्तर [1] ने सुझाव दिया कि एक फ़ाइलनाम में रिक्त स्थान से बच सकते हैं, यहां सुझाए गए अन्य समाधानों के लिए एक मूल्यवान विकल्प है (जैसे कि व्हाट्सएप के बजाय एक विभाजक के रूप में एक अशक्त चरित्र का उपयोग करना)। लेकिन यह सरल हो सकता है - आपको वास्तव में एक अद्वितीय चरित्र की आवश्यकता नहीं है। आप सीधे बची हुई जगहों को सीधे जोड़ सकते हैं:

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

इसके अलावा, grep केवल तभी आवश्यक है जब आप केवल नामों वाली जगहों के साथ फाइल चाहते हैं। अधिक उदारतापूर्वक (उदाहरण के लिए, जब किसी स्थान पर फ़ाइलों का एक बैच संसाधित करते हैं, तो कुछ नहीं), बस grep को छोड़ दें:

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

फिर, निश्चित रूप से, फ़ाइल नाम में रिक्त स्थान (जैसे, टैब) की तुलना में अन्य व्हाट्सएप हो सकते हैं:

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

यह मानता है कि आपके पास एक sed है, जो समर्थन करता है -r (विस्तारित रेगेक्स) जैसे कि GNU sed या bsd sed के हाल के संस्करण (जैसे, FreeBSD जो मूल रूप से FreeBSD 8 से पहले "-E" विकल्प को वर्तनी देता है और संगतता के लिए -r औरE दोनों का समर्थन करता है। FreeBSD 11 के माध्यम से कम से कम)। अन्यथा आप एक मूल रेगेक्स वर्ण वर्ग ब्रैकेट अभिव्यक्ति का उपयोग कर सकते हैं और मैन्युअल रूप से []सीमांकक में अंतरिक्ष और टैब वर्ण दर्ज कर सकते हैं ।

[१] यह टिप्पणी के रूप में शायद अधिक उपयुक्त है या उस उत्तर के लिए संपादित है, लेकिन फिलहाल मेरे पास टिप्पणी करने के लिए पर्याप्त प्रतिष्ठा नहीं है और केवल संपादन का सुझाव दे सकता है। चूँकि ऊपर के बाद के रूप (बिना grep) डिक के व्यवहार को बदल देते हैं। गर्टिन का मूल उत्तर, एक सीधा संपादन शायद वैसे भी उचित नहीं है।


1
पागल यूनिक्स लोग, जो स्क्रिप्ट को अपने आउटपुट पर विचार किए बिना नाम चलाते हैं, वो है
andrew lorien

4

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

ध्यान दें कि ऊपर दिए गए आदेश में, प्रत्येक फ़ाइल के लिए नए सिरे xargsसे कॉल करेगा mplayer। यह अवांछनीय हो सकता है mplayer, लेकिन अन्य लक्ष्यों के लिए ठीक हो सकता है।


1
मौजूदा उत्तरों के लिए एक उपयोगी इसके अलावा, लेकिन यह ध्यान देने योग्य होगा कि यह mplayerप्रत्येक फ़ाइल के लिए नए सिरे से कहा जाएगा। यह मायने रखता है यदि आप प्रयास करते हैं जैसे ... | xargs -I{} mplayer -shuffle {}: यह पूरी तरह से निर्धारक क्रम में खेलेंगे, इसके बावजूद -shuffle

1
यह आमतौर पर इरादा नहीं है। xargsज्यादातर कमांड के साथ उपयोग किया जाता है जो फ़ाइल नामों की एक सूची को स्वीकार करते हैं (आसान उदाहरण rm:), और प्रत्येक इनवोकेशन में जितने फिट हो सकते हैं उतने ही फ़ाइल नाम से गुजरने का प्रयास करते हैं, यदि आवश्यक हो तो कई इनवॉइस में विभाजित हो सकते हैं। जब आप एक कमांड का उपयोग करते हैं, तो आप अंतर देख सकते हैं, जैसे कि प्रत्येक इनवोकेशन दिखाई देता है, जैसे echo(डिफ़ॉल्ट): seq 0 100000 | xargs0 से 23695 तक सभी नंबरों को प्रिंट करता है (प्लेटफ़ॉर्म-विशिष्ट, लेकिन यही मेरे सिस्टम पर होता है) पहली पंक्ति में, 45539 पर लाइन 2 पर, आदि और आप सही हैं, अधिकांश आदेशों के लिए, यह कोई फर्क नहीं पड़ेगा।

4

MacOS 10.12.x (Sierra) पर, यदि आपके पास फ़ाइल नाम या उपनिर्देशिका में स्थान हैं, तो आप निम्नलिखित का उपयोग कर सकते हैं:

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

2

यह निर्भर करता है (क) आप 7 नंबर से जुड़े हुए हैं, कहे, नींबू, और (ख) क्या आपकी फ़ाइल के किसी भी नाम में नई लाइनें हैं (और क्या आप उन्हें नाम बदलने के लिए तैयार हैं)।

इससे निपटने के कई तरीके हैं, लेकिन उनमें से कुछ हैं:

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

readयदि फ़ाइल नाम नई पंक्तियां शामिल पाश काम नहीं करता है; अन्य लोग नामों में नई संख्या के साथ भी सही ढंग से काम करते हैं (अकेले स्थान दें)। मेरे पैसे के लिए, यदि आपके पास नई नाम वाली फ़ाइल नाम है, तो आपको नई नाम के बिना फ़ाइल का नाम बदलना चाहिए। फ़ाइल नाम के आसपास दोहरे उद्धरण चिह्नों का उपयोग करना सही ढंग से काम करने वाले छोरों की कुंजी है।

यदि आपके पास GNU findऔर GNU xargs(या FreeBSD (* BSD?), या Mac OS X) हैं, तो आप निम्न -print0और -0विकल्पों का भी उपयोग कर सकते हैं , जैसे कि:

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

यह नाम की सामग्री की परवाह किए बिना काम करता है (केवल दो वर्ण जो फ़ाइल नाम में प्रकट नहीं हो सकते हैं वे स्लैश और NUL हैं, और स्लैश फ़ाइल पथ में कोई समस्या नहीं पैदा करता है, इसलिए NUL का उपयोग करके जैसा कि नाम सीमांकक सब कुछ कवर करता है)। हालाँकि, यदि आपको पहले 6 प्रविष्टियों को फ़िल्टर करने की आवश्यकता है, तो आपको एक ऐसे प्रोग्राम की आवश्यकता है जो न्यूलाइन के बजाय NUL द्वारा समाप्त की गई 'लाइनों' को संभालता हो ... और मुझे यकीन नहीं है कि कोई भी है।

पहली बार हाथ पर विशिष्ट मामले के लिए सबसे सरल है; हालाँकि, यह आपके अन्य परिदृश्यों को कवर करने के लिए सामान्यीकृत नहीं हो सकता है जिन्हें आपने अभी तक सूचीबद्ध नहीं किया है।


2

मुझे पता है कि मैं जवाब दे नहीं कर रहा हूँ xargsसवाल सीधे लेकिन यह की कीमत का उल्लेख findके -execविकल्प।

निम्नलिखित फाइल सिस्टम को देखते हुए:

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

0 directories, 4 files

ड्रीम थियेटर और किंग्स एक्स में स्थान को संभालने के लिए खोज कमांड बनाया जा सकता है। इसलिए, ट्रे का उपयोग करके प्रत्येक बैंड के ड्रमर्स को खोजने के लिए:

[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

में -execविकल्प {}पथ सहित फ़ाइल नाम के लिए खड़ा है। ध्यान दें कि आपको इससे बचना नहीं है या इसे उद्धरण में नहीं रखना है।

-exec'S टर्मिनेटर ( +और \;) के बीच का अंतर यह है कि +समूह कई फ़ाइल नामों के रूप में है जो यह एक कमांड लाइन पर कर सकते हैं। जबकि \;प्रत्येक फ़ाइल के नाम के लिए कमांड निष्पादित करेगा।

तो, find bands/ -type f -exec grep Drums {} +परिणाम होगा:

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

और find bands/ -type f -exec grep Drums {} \;परिणाम होगा:

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

इस के मामले में grepफ़ाइल नाम को मुद्रित करने या न करने का दुष्प्रभाव है।

[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

बेशक, grepके विकल्प -hऔर -Hयह नियंत्रित करेंगे कि नाम कैसे grepकहा जाता है, चाहे उसका नाम छपा हो या नहीं ।


xargs

xargs यह भी नियंत्रित कर सकते हैं कि कैसे आदमी फाइलें कमांड लाइन पर हैं।

xargsडिफ़ॉल्ट समूहों द्वारा एक पंक्ति में सभी तर्क। आदेश का उपयोग करने के लिए वही काम -exec \;करने के लिए xargs -l। ध्यान दें कि -tविकल्प xargsइसे निष्पादित करने से पहले कमांड प्रिंट करना बताता है।

[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

देखें कि -lविकल्प xargs को हर फ़ाइलनाम के लिए grep निष्पादित करने के लिए कहता है।

डिफ़ॉल्ट (अर्थात कोई -lविकल्प नहीं ):

[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

xargsकमांड लाइन पर कितनी फाइलें हो सकती हैं, इस पर बेहतर नियंत्रण है। -lविकल्प को प्रति कमांड फाइलों की अधिकतम संख्या दें ।

[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]# 

देखें कि grepकिस वजह से दो फ़ाइलनामों के साथ निष्पादित किया गया था -l2


1

इस पोस्ट के विशिष्ट शीर्षक को देखते हुए, यहाँ मेरा सुझाव है:

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

विचार किसी भी विशिष्ट वर्ण में रिक्त स्थान को परिवर्तित करने के लिए है, जैसे '<', और उसके बाद उसे '\' में बदल दें, एक रिक्त के बाद एक बैकस्लैश। फिर आप अपनी पसंद के किसी भी कमांड में पाइप कर सकते हैं, जैसे:

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

यहाँ कुंजी 'tr' और 'sed' कमांड्स में निहित है; और आप '<', जैसे 'के अलावा किसी भी वर्ण का उपयोग कर सकते हैं?' या यहां तक ​​कि एक टैब-चरित्र भी।


के माध्यम से चक्कर का उद्देश्य क्या है tr? सिर्फ क्यों नहीं ls *.mp3 | sed -n '7!b;s/\([[:space:]]\)/\\\1/g;p'?
16

1
मैंने पाया है कि "tr '' '?" "" Sed "की आवश्यकता को समाप्त करता है। अकेला "?" चरित्र गैर-रिक्त है, लेकिन इस मामले में किसी भी एकल वर्ण से मेल खाता है: रिक्त। यह कुछ और होने की संभावना काफी छोटी है, और स्वीकार्य है क्योंकि आप .mp3 में समाप्त होने वाली सभी फ़ाइलों को संसाधित करने का प्रयास कर रहे हैं: "ls | grep '' | tr '' '?' | xargs -L1 GetFileInfo ”
डिक

आप एक ही समय में "टैब" भी संभाल सकते हैं: tr '\ t' '??' दोनों को संभालता है।
डिक गुर्टिन

1

वैकल्पिक समाधान सहायक हो सकते हैं ...

आप पर्ल का उपयोग करके अपनी लाइनों के अंत में एक अशक्त चरित्र भी जोड़ सकते हैं, फिर -0xargs में विकल्प का उपयोग करें । Xargs -d '\ n' (स्वीकृत उत्तर में) के विपरीत - यह OS X सहित हर जगह काम करता है।

उदाहरण के लिए, पुनरावर्ती सूची (निष्पादित करना, स्थानांतरित करना, आदि) के लिए MPEG3 फाइलें जिसमें रिक्त स्थान या अन्य मजाकिया अक्षर हो सकते हैं - मैं उपयोग करूंगा:

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

(नोट: फ़िल्टरिंग के लिए, मुझे आसान-से-याद रखना पसंद है "| grep" सिंटैक्स को "ढूंढने के लिए" नाम तर्क।)

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.