Xargs के साथ कई कमांड चल रहे हैं


310
cat a.txt | xargs -I % echo %

ऊपर दिए गए उदाहरण में, xargs echo %कमांड तर्क के रूप में लेता है। लेकिन कुछ मामलों में, मुझे एक के बजाय तर्क को संसाधित करने के लिए कई आदेशों की आवश्यकता होती है। उदाहरण के लिए:

cat a.txt | xargs -I % {command1; command2; ... }

लेकिन xargs इस फॉर्म को स्वीकार नहीं करते हैं। एक समाधान मुझे पता है कि मैं कमांड को लपेटने के लिए एक फ़ंक्शन को परिभाषित कर सकता हूं, लेकिन यह एक पाइपलाइन नहीं है, मैं इसे पसंद नहीं करता। क्या कोई और उपाय है?


1
इनमें से अधिकांश उत्तर सुरक्षा कमजोरियां हैंसंभावित अच्छे उत्तर के लिए यहां देखें।
मतीन उलहाक

2
मैं लगभग सभी चीज़ों के लिए xargs का उपयोग करता हूं, लेकिन मुझे स्ट्रिंग्स के अंदर कमांड डालने से नफरत है और स्पष्ट रूप से उप-समूह बनाना है। मैं सीखने की कगार पर हूं कि कैसे एक whileलूप में पाइप किया जाए जिसमें कई कमांड हो सकते हैं।
श्रीधर सरनोबत

जवाबों:


443
cat a.txt | xargs -d $'\n' sh -c 'for arg do command1 "$arg"; command2 "$arg"; ...; done' _

... या, बिल्ली के बेकार उपयोग के बिना :

<a.txt xargs -d $'\n' sh -c 'for arg do command1 "$arg"; command2 "$arg"; ...; done' _

कुछ बारीकियों को समझाने के लिए:

  • इसके "$arg"बजाय %(और कमांड लाइन -Iमें अनुपस्थिति xargs) का उपयोग सुरक्षा कारणों से होता है: डेटा shको कोड में प्रतिस्थापित करने के बजाय कमांड-लाइन तर्क सूची पर पास करना सामग्री को रोकता है जिसमें डेटा हो सकता है (जैसे कि $(rm -rf ~), विशेष रूप से लेने के लिए) दुर्भावनापूर्ण उदाहरण) कोड के रूप में निष्पादित होने से।

  • इसी तरह, -d $'\n'एक GNU एक्सटेंशन का उपयोग होता है जो xargsइनपुट फ़ाइल की प्रत्येक पंक्ति को एक अलग डेटा आइटम के रूप में मानता है। या तो यह -0(जो न्यूलाइन्स के बजाय एनयूएल की अपेक्षा करता है) शेल्स को लागू करने के लिए शेल-जैसे (लेकिन काफी शेल-संगत नहीं) को पढ़ने की कोशिश करने से रोकने के लिए आवश्यक है। (यदि आपके पास GNU xargs नहीं है, तो आप tr '\n' '\0' <a.txt | xargs -0 ...बिना लाइन-रीडिंग प्राप्त करने के लिए उपयोग कर सकते हैं -d)।

  • इसके _लिए एक प्लेसहोल्डर है $0, जैसे कि अन्य डेटा मान xargsबनते हैं $1और आगे बढ़ते हैं, जो उन मानों का डिफ़ॉल्ट सेट होता है जो forलूप से अधिक होता है।


58
उन अपरिचित लोगों के लिए sh -c- ध्यान दें कि प्रत्येक कमांड के बाद अर्धविराम वैकल्पिक नहीं है, भले ही यह सूची में अंतिम कमांड हो।
नूह ससम्मान

6
कम से कम मेरे कॉन्फ़िगरेशन पर, प्रारंभिक "{" के तुरंत बाद एक स्थान होना चाहिए। समाप्त होने वाले घुंघराले ब्रेस से पहले किसी भी स्थान की आवश्यकता नहीं है, लेकिन जैसा कि श्री सुस्मान ने कहा, आपको एक समापन अर्धविराम की आवश्यकता है।
१३:

4
इस उत्तर में पहले के आसपास घुंघराले ब्रेसिज़ थे command1और command2; मुझे बाद में एहसास हुआ कि वे आवश्यक नहीं हैं।
कीथ थॉम्पसन

24
अर्धविराम के बारे में उपरोक्त टिप्पणियों को स्पष्ट करने के लिए, समापन से पहले अर्धविराम की आवश्यकता होती है }: sh -c '{ command1; command2; }' -- but it's not required at the end of a command sequence that doesn't use braces: sh -c 'command1; कमांड 2'`
कीथ थॉम्पसन

8
यदि आप %अपने स्ट्रिंग में कहीं और चरित्र को शामिल करते हैं sh -c, तो यह सुरक्षा कमजोरियों से ग्रस्त है: एक फ़ाइल नाम युक्त $(rm -rf ~)'$(rm -rf ~)'(और यह एक सामान्य कानूनी फ़ाइल सिस्टम पर फ़ाइल नाम के भीतर होने के लिए एक कानूनी विकल्प है!) किसी को बहुत खराब दिन का कारण बनेगा। ।
चार्ल्स डफी

35

GNU समानांतर के साथ आप कर सकते हैं:

cat a.txt | parallel 'command1 {}; command2 {}; ...; '

अधिक जानने के लिए इंट्रो वीडियो देखें: https://www.youtube.com/playlist?list=PL284C9FF2488BC4D1

सुरक्षा कारणों से यह अनुशंसा की जाती है कि आप इंस्टॉल करने के लिए अपने पैकेज मैनेजर का उपयोग करें। लेकिन अगर आप ऐसा नहीं कर सकते हैं तो आप इस 10 सेकंड की स्थापना का उपयोग कर सकते हैं।

10 सेकंड की स्थापना एक पूर्ण स्थापना करने की कोशिश करेगी; यदि वह विफल रहता है, तो एक व्यक्तिगत स्थापना; यदि वह विफल रहता है, तो एक न्यूनतम स्थापना।

$ (wget -O - pi.dk/3 || lynx -source pi.dk/3 || curl pi.dk/3/ || \
   fetch -o - http://pi.dk/3 ) > install.sh
$ sha1sum install.sh | grep 3374ec53bacb199b245af2dda86df6c9
12345678 3374ec53 bacb199b 245af2dd a86df6c9
$ md5sum install.sh | grep 029a9ac06e8b5bc6052eac57b2c3c9ca
029a9ac0 6e8b5bc6 052eac57 b2c3c9ca
$ sha512sum install.sh | grep f517006d9897747bed8a4694b1acba1b
40f53af6 9e20dae5 713ba06c f517006d 9897747b ed8a4694 b1acba1b 1464beb4
60055629 3f2356f3 3e9c4e3c 76e3f3af a9db4b32 bd33322b 975696fc e6b23cfb
$ bash install.sh

56
अज्ञात साइटों से यादृच्छिक स्क्रिप्ट चलाने के माध्यम से उपकरण स्थापित करना भयानक अभ्यास है। लोकप्रिय डिस्ट्रोस के समानांतर समानांतर टिकीलॉल पैकेज हैं, जिन पर भरोसा किया जा सकता है (कुछ विस्तार से) यादृच्छिक
w3 की

4
आइए देखते हैं कि सबसे आसान अटैक वेक्टर क्या है: Pi.dk को GNU Parallel के लेखक द्वारा नियंत्रित किया जाता है, इसलिए यह हमला करने के लिए कि आपको सर्वर में तोड़ना होगा या DNS पर ले जाना होगा। वितरण के आधिकारिक पैकेज को संभालने के लिए, आप अक्सर पैकेज को बनाए रखने के लिए बस स्वयंसेवक कर सकते हैं। इसलिए जब आप सामान्य रूप से सही हो सकते हैं, तो ऐसा लगता है कि इस विशेष मामले में आपकी टिप्पणी उचित नहीं है।
ओले तांगे

10
व्यवहार में मुझे नहीं पता है कि pi.dk लेखक का है। वास्तव में यह सत्यापित करते हुए कि यह मामला है, यह सोचकर कि ws में ssl का उपयोग कैसे करना है और यह जाँचना कि यह कमांड वही करता है जो यह करना है कि यह थोड़ा काम है। आपका कहना है कि आधिकारिक पैकेज में दुर्भावनापूर्ण कोड हो सकता है, यह सच है, लेकिन यह भी wget पैकेज के लिए है।
फाबियान

3
यह सबसे अच्छा समाधान नहीं हो सकता है अगर ओपी निष्पादित करना चाहता है, तो प्रत्येक आदेश अनुक्रमिक, सही होना चाहिए?
इकारियनकंपलेक्स

2
@IcarianComplex Add -j1 इसे ठीक करेगा।
ओले तांगे

26

यह xargs के बिना सिर्फ एक और दृष्टिकोण है और न ही बिल्ली:

while read stuff; do
  command1 "$stuff"
  command2 "$stuff"
  ...
done < a.txt

2
बग्गी, जैसा दिया गया। जब तक आप स्पष्ट नहीं करते हैं IFS, तब तक यह फ़ाइल नाम में व्हाट्सएप के प्रमुख और अनुगामी को अनदेखा करेगा; जब तक आप नहीं जोड़ते हैं -r, तब तक शाब्दिक बैकस्लैश वाले फ़ाइलनामों में उन पात्रों को अनदेखा किया जाएगा।
चार्ल्स डफी

सवाल का जवाब नहीं देता। इसके बारे में विशेष रूप से पूछा xargs। (यह जीएनयू के लिए इसी तरह कुछ करने के लिए विस्तार करने के लिए कठिन है xargs' -P<n>विकल्प)
डेन बर्ग गर्ट वैन

1
यह पूरी तरह से अच्छी तरह से काम करता है। आप इसे एक पाइप्ड कमांड के रूप में भी उपयोग कर सकते हैं जैसे$ command | while read line; do c1 $line; c2 $line; done
एलेक्सर

25

आप उपयोग कर सकते हैं

cat file.txt | xargs -i  sh -c 'command {} | command2 {} && command3 {}'

{} = पाठ फ़ाइल पर प्रत्येक पंक्ति के लिए चर


8
यह असुरक्षित है। क्या होगा अगर आपके विकल्प के रूप file.txtमें एक डेटम शामिल है $(rm -rf ~)?
चार्ल्स डफी

19

एक बात जो मैं करने के लिए इस समारोह में .bashrc / .profile जोड़ने के लिए है:

function each() {
    while read line; do
        for f in "$@"; do
            $f $line
        done
    done
}

फिर आप जैसे काम कर सकते हैं

... | each command1 command2 "command3 has spaces"

जो xargs या -exec से कम क्रिया है। यदि आप उस व्यवहार की भी आवश्यकता है, तो आप प्रत्येक में कमांड में मनमाने स्थान पर रीड से मान डालने के लिए फ़ंक्शन को संशोधित कर सकते हैं।


1
बिना जवाब दिए, यह बेहद आसान है
charlesreid1

15

मैं ऐसी शैली पसंद करता हूं जो शुष्क रन मोड (बिना | sh) की अनुमति देता है :

cat a.txt | xargs -I % echo "command1; command2; ... " | sh

पाइप के साथ भी काम करता है:

cat a.txt | xargs -I % echo "echo % | cat " | sh

2
यह काम करता है, जब तक कि आप GNU xargs के -Pविकल्प का उपयोग नहीं करना चाहते हैं ... (यदि नहीं, तो मैं ज्यादातर उपयोग -execकरता findहूं, क्योंकि मेरे इनपुट ज्यादातर फ़ाइलनाम हैं)
Gert van den Berg

13

पार्टी में थोड़ी देर हो गई।

मैं माइग्रेट करने से पहले अपनी निर्देशिका को हजारों छोटी फ़ाइलों के साथ संपीड़ित करने के लिए नीचे प्रारूप का उपयोग करता हूं। यदि आपको कमांड के अंदर सिंगल कोट्स की आवश्यकता नहीं है, तो यह काम करना चाहिए।

कुछ संशोधन के साथ, मुझे यकीन है कि यह किसी के लिए उपयोगी होगा। Cygwin(बाबुन) में परीक्षण किया गया

find . -maxdepth 1 ! -path . -type d -print0 | xargs -0 -I @@ bash -c '{ tar caf "@@.tar.lzop" "@@" && echo Completed compressing directory "@@" ; }'

find .यहाँ खोजें
-maxdepth 1बच्चे निर्देशिका में मत जाओ
! -path .। / करंट डायरेक्टरी पाथ
-type dमैच केवल डाइरेक्टरीज़ को
-print0अलग करता है null bytes \ 0
| xargsपाइप से अलग आउटपुट xargs
-0इनपुट के लिए null अलग बाइट्स अलग है
-I @@प्लेसहोल्डर @@ है। @@ को इनपुट से बदलें।
bash -c '...'बैश कमांड कमांड
{...}कमांड को
&&निष्पादित करें अगला कमांड तभी निष्पादित करें जब पिछली कमांड सफलतापूर्वक समाप्त हो गई हो (बाहर निकलें 0)

अंतिम ;महत्वपूर्ण है, अन्यथा यह विफल हो जाएगा।

आउटपुट:

Completed compressing directory ./Directory1 with meta characters in it
Completed compressing directory ./Directory2 with meta characters in it
Completed compressing directory ./Directory3 with meta characters in it

2018 जुलाई अपडेट:

अगर आपको हैक्स और आसपास खेलना पसंद है, तो यहां कुछ दिलचस्प है:

echo "a b c" > a.txt
echo "123" >> a.txt
echo "###this is a comment" >> a.txt
cat a.txt
myCommandWithDifferentQuotes=$(cat <<'EOF'                                     
echo "command 1: $@"; echo 'will you do the fandango?'; echo "command 2: $@"; echo
EOF
)
< a.txt xargs -I @@ bash -c "$myCommandWithDifferentQuotes" -- @@

आउटपुट:

command 1: a b c
will you do the fandango?
command 2: a b c

command 1: 123
will you do the fandango?
command 2: 123

command 1: ###this is a comment
will you do the fandango?
command 2: ###this is a comment

स्पष्टीकरण:
- एक भी लाइनर स्क्रिप्ट बनाएं और एक चर में संग्रहीत
- xargs पढ़ता है a.txtऔर के रूप में कार्यान्वित यह bashस्क्रिप्ट
- @@ यकीन है कि हर बार एक पूरी लाइन पारित हो जाता है बनाता है
- लाना @@के बाद --यकीन है कि बनाता है @@के लिए स्थितीय पैरामीटर इनपुट के रूप में लिया जाता है bashआदेश, नहीं एक bashशुरुआत OPTION, यानी -cअपने आप जैसा मतलब हैrun command

--जादुई है, यह कई अन्य चीजों के साथ काम करता है, अर्थात ssh, यहां तक ​​किkubectl


1
मैंने इस प्रकार की चीज़ के साथ एक सेटअप का उपयोग किया है: find . -type f -print0|xargs -r0 -n1 -P20 bash -c 'f="{}";ls -l "$f"; gzip -9 "$f"; ls -l "$f.gz"'(छोरों को परिवर्तित करते समय यह थोड़ा आसान है)
गर्ट वैन डेन बर्ग

1
मेरी पिछली टिप्पणी के लिए देर से संपादित करें: (यदि फ़ाइलनाम में दोहरे उद्धरण सम्‍मिलित हैं तो सुरक्षा मुद्दा है ...) (ऐसा लगता "$@"है कि इससे बचने का एकमात्र तरीका है ... ( -n1यदि आप मापदंडों की संख्या को सीमित करना चाहते हैं)
Gert van den Berg

यह ध्यान दिया जाना चाहिए कि --शेल द्वारा यह कहने के लिए उपयोग किया जाता है कि कोई और विकल्प स्वीकार नहीं किया जाना है। यह वहाँ के -बाद --भी होने की अनुमति देता है। यदि आप grep -rपैटर्न में शामिल हैं, तो आप बहुत ही रोचक और भ्रामक आउटपुट प्राप्त कर सकते हैं -। जिस तरह से आप इसे स्पष्ट करते हैं, हालांकि यह स्पष्ट नहीं करता है कि यह कैसे काम करता है। Iirc यह एक POSIX बात है, लेकिन वैसे भी यह इस ओर इशारा करने लायक है, मुझे लगता है। बस कुछ विचार करने के लिए। और मुझे लगता है कि बोनस btw प्यार करता हूँ!
प्रिएफ्टन

10

यह सबसे सुरक्षित संस्करण लगता है।

tr '[\n]' '[\0]' < a.txt | xargs -r0 /bin/bash -c 'command1 "$@"; command2 "$@";' ''

( -0हटाया जा सकता है और trएक रीडायरेक्ट के साथ बदल दिया (या फ़ाइल एक अशक्त साथ बदला जा सकता बजाय फ़ाइल विभाजित)। यह वहाँ में मुख्य रूप से है, क्योंकि मैं मुख्य रूप से उपयोग करने xargsके साथ findसाथ -print0उत्पादन) (यह भी पर प्रासंगिक हो सकता है xargsबिना संस्करणों -0विस्तार)

यह सुरक्षित है, क्योंकि आर्ग्स इसे निष्पादित करते समय एक सरणी के रूप में शेल को पैरामीटर पास करेगा। शेल (कम से कम bash) तब उन्हें अन्य प्रक्रियाओं के लिए एक अनछुए सरणी के रूप में पारित करेगा जब सभी का उपयोग करके प्राप्त किया जाता है["$@"][1]

यदि आप उपयोग करते हैं ...| xargs -r0 -I{} bash -c 'f="{}"; command "$f";' '', तो स्ट्रिंग दोहरे उद्धरण में होने पर असाइनमेंट विफल हो जाएगा। यह प्रत्येक संस्करण का उपयोग करने -iया के लिए सही है -I। (इसे एक स्ट्रिंग में बदलने के कारण, आप हमेशा इनपुट डेटा में अनपेक्षित वर्ण (जैसे उद्धरण, बैकटिक्स या डॉलर संकेत) सम्मिलित करके कमांड इंजेक्ट कर सकते हैं)

यदि आदेश एक समय में केवल एक पैरामीटर ले सकते हैं:

tr '[\n]' '[\0]' < a.txt | xargs -r0 -n1 /bin/bash -c 'command1 "$@"; command2 "$@";' ''

या कुछ हद तक कम प्रक्रियाओं के साथ:

tr '[\n]' '[\0]' < a.txt | xargs -r0 /bin/bash -c 'for f in "$@"; do command1 "$f"; command2 "$f"; done;' ''

यदि आपके पास विस्तार के xargsसाथ GNU या कोई अन्य है -Pऔर आप समानांतर में 32 प्रक्रियाएँ चलाना चाहते हैं, तो प्रत्येक में प्रत्येक कमांड के लिए 10 से अधिक पैरामीटर नहीं हैं:

tr '[\n]' '[\0]' < a.txt | xargs -r0 -n10 -P32 /bin/bash -c 'command1 "$@"; command2 "$@";' ''

यह इनपुट में किसी विशेष वर्ण के खिलाफ मजबूत होना चाहिए। (यदि इनपुट को अलग कर दिया गया है।) trयदि कुछ पंक्तियों में नई-नई लाइनें हैं, तो संस्करण को कुछ अमान्य इनपुट मिलेंगे, लेकिन यह एक नई पंक्तिबद्ध फ़ाइल के साथ अपरिहार्य है।

इसके लिए रिक्त पहला पैरामीटर bash -cइसके कारण है: ( bashमैन पेज से ) (साभार @clacke)

-c   If the -c option is present, then  commands  are  read  from  the  first  non-option  argument  com
     mand_string.   If there are arguments after the command_string, the first argument is assigned to $0
     and any remaining arguments are assigned to the positional parameters.  The assignment  to  $0  sets
     the name of the shell, which is used in warning and error messages.

यह फ़ाइल नाम में दोहरे उद्धरण चिह्नों के साथ भी काम करना चाहिए। इसके लिए एक शेल की आवश्यकता होती है जो ठीक से समर्थन करे"$@"
गर्ट वैन डेन बर्ग

आप argv को याद कर रहे हैं [0] बहस करने के लिए। bash -c 'command1 "$@"; command2 "$@";' arbitrarytextgoeshere
क्लेक

3
यह xargs क्या करता है के बारे में नहीं है। bashके साथ -cपहले (आदेशों के बाद) एक तर्क है कि प्रक्रिया का नाम होगा, तो यह स्थितिगत तर्क लेता है। कोशिश करें bash -c 'echo "$@" ' 1 2 3 4और देखें कि क्या सामने आता है।
ताली

यह एक अच्छा संस्करण है जो बॉबी-टैब्लेट प्राप्त नहीं करता है।
मतीन उल्हाक

8

एक और संभावित समाधान जो मेरे लिए काम करता है वह कुछ इस तरह है -

cat a.txt | xargs bash -c 'command1 $@; command2 $@' bash

नोट 'बैश' के अंत में - मुझे लगता है कि इसे bash के रूप में argv [0] के रूप में पारित किया गया है। इस सिंटैक्स में इसके बिना प्रत्येक कमांड का पहला पैरामीटर खो गया है। यह कोई भी शब्द हो सकता है।

उदाहरण:

cat a.txt | xargs -n 5 bash -c 'echo -n `date +%Y%m%d-%H%M%S:` ; echo " data: " $@; echo "data again: " $@' bash

5
यदि आप बोली नहीं लगाते हैं "$@", तो आप स्ट्रिंग-स्प्लिटिंग और ग्लोब-विस्तार कर रहे हैं तर्क सूची।
चार्ल्स डफी

2

इसके लिए मेरा वर्तमान बीकेएम है

... | xargs -n1 -I % perl -e 'system("echo 1 %"); system("echo 2 %");'

यह दुर्भाग्यपूर्ण है कि यह पर्ल का उपयोग करता है, जो बैश की तुलना में स्थापित होने की संभावना कम है; लेकिन यह अधिक इनपुट को संभालता है जो स्वीकृत उत्तर है। (मैं एक सर्वव्यापी संस्करण का स्वागत करता हूं जो पर्ल पर भरोसा नहीं करता है।)

@ कीथथम्पसन का सुझाव

 ... | xargs -I % sh -c 'command1; command2; ...'

बहुत अच्छा है - जब तक कि आपके इनपुट में शेल कमेंट कैरेक्टर # नहीं है, तब तक पहले कमांड का हिस्सा और दूसरा कमांड का सभी भाग छोटा हो जाएगा।

Hashes # काफी सामान्य हो सकता है, यदि इनपुट एक फाइलसिस्टम लिस्टिंग से लिया गया है, जैसे कि ls या find, और आपका एडिटर उनके नाम पर # के साथ अस्थायी फाइल बनाता है।

समस्या का उदाहरण:

$ bash 1366 $>  /bin/ls | cat
#Makefile#
#README#
Makefile
README

ओह, यहाँ समस्या है:

$ bash 1367 $>  ls | xargs -n1 -I % sh -i -c 'echo 1 %; echo 2 %'
1
1
1
1 Makefile
2 Makefile
1 README
2 README

आह, यह बेहतर है:

$ bash 1368 $>  ls | xargs -n1 -I % perl -e 'system("echo 1 %"); system("echo 2 %");'
1 #Makefile#
2 #Makefile#
1 #README#
2 #README#
1 Makefile
2 Makefile
1 README
2 README
$ bash 1369 $>  

5
# समस्या easly उद्धरण का उपयोग कर हल किया जा सकता:ls | xargs -I % sh -c 'echo 1 "%"; echo 2 "%"'
जीपीएल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.