प्रत्येक लाइन के इनपुट के लिए xargs कमांड को एक बार निष्पादित करें


341

मैं दिए गए इनपुट की प्रत्येक पंक्ति के लिए एक बार ठीक से कमांड निष्पादित कैसे कर सकता हूं? यह डिफ़ॉल्ट व्यवहार है लाइनों को चोक करना और कमांड को एक बार निष्पादित करना, प्रत्येक उदाहरण के लिए कई लाइनें पास करना।

से http://en.wikipedia.org/wiki/Xargs :

find / path -type f -print0 | xargs -0 rm

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

/ पाथ-टाइप f -exec rm '{}' '\;

मुझे पता है कि खोज में "निष्पादन" झंडा है। मैं दूसरे संसाधन से सिर्फ एक उदाहरण प्रस्तुत कर रहा हूं।


4
आपके द्वारा दिए गए उदाहरण में, find /path -type f -deleteऔर भी अधिक कुशल होगा :)
tzot

xargs का उपयोग न करने का प्रयास करें ...
Naib

6
ओपी, मुझे पता है कि यह प्रश्न बहुत पुराना है, लेकिन यह अभी भी Google और IMHO पर आता है, स्वीकृत उत्तर गलत है। नीचे मेरे लंबे उत्तर देखें।
टोबिया

कृपया अपनी स्वीकारोक्ति को @ टोबिया के उत्तर पर स्विच करने पर विचार करें जो बहुत बेहतर है। स्वीकृत उत्तर नामों में रिक्त स्थान को संभालता नहीं है और xargs कमांड के लिए कई तर्क नहीं देता है जो xargs की मुख्य विशेषताओं में से एक है।
ग्रे

जवाबों:


392

यदि आपके इनपुट में स्थान नहीं है तो केवल निम्नलिखित कार्य करेंगे:

xargs -L 1
xargs --max-lines=1 # synonym for the -L option

मैन पेज से:

-L max-lines
          Use at most max-lines nonblank input lines per command line.
          Trailing blanks cause an input line to be logically continued  on
          the next input line.  Implies -x.

13
मेरे लिए यह उस तरह से हो सकता है जैसा xargs -n 1आपने "तर्क सूची को बहुत लंबा दिखाया"।
वर्नट

19
यदि MAX-LINESइसे छोड़ दिया जाए तो यह 1 से चूक जाता है, इस प्रकार xargs -lयह पर्याप्त है। देख लो info xargs
थोर

3
@Wernight: "-n1" प्रति इनपुट लाइन में 1 आह्वान नहीं देता है। शायद आपकी इनपुट लाइन बहुत लंबी थी। डेमो: echo "foo bar" | xargs -n1 echo। इसलिए यदि आप 'ls' जैसी सामग्री में पाइप करते हैं, तो यह रिक्त स्थान को अच्छी तरह से संभाल नहीं पाएगा।
gatoatigrado

8
ये गलत है। -L 1मूल प्रश्न का उत्तर नहीं देता है, और -n 1ऐसा केवल एक संभावित व्याख्या में होता है। नीचे मेरा लंबा जवाब देखें।
टोबिया

2
@ टोबिया: यह मूल प्रश्न का उत्तर देता है, जो विशेष रूप से इनपुट की लाइनों के बारे में था। बिलकुल यही -L 1करता है। मेरे लिए, ओपी स्पष्ट रूप से डिफ़ॉल्ट chunking व्यवहार से बचने की कोशिश कर रहा था, और जब से यह स्वीकार किया गया था मुझे लगता है कि मैं सही था। आपका उत्तर थोड़ा अलग उपयोग-मामले को संबोधित करता है जहाँ आप रूखा व्यवहार चाहते हैं।
डेमॉन

207

ऐसा लगता है कि इस पृष्ठ पर सभी मौजूदा उत्तर गलत हैं, जिनमें से एक को सही के रूप में चिह्नित किया गया है। यह इस तथ्य से उपजा है कि प्रश्न अस्पष्ट शब्द है।

सारांश:   यदि आप दिए गए इनपुट के प्रत्येक लाइन के लिए "बिल्कुल एक बार" कमांड को निष्पादित करना चाहते हैं , तो पूरी लाइन (न्यूलाइन के बिना) को कमांड में एक ही तर्क के रूप में पास करना है, तो यह करने के लिए सबसे अच्छा यूनिक्स-संगत तरीका है:

... | tr '\n' '\0' | xargs -0 -n1 ...

जीएनयू xargsमें उपयोगी एक्सटेंशन हो सकते हैं या नहीं हो सकते हैं जो आपको दूर करने की अनुमति देते हैं tr, लेकिन वे ओएस एक्स और अन्य यूनिक्स प्रणालियों पर उपलब्ध नहीं हैं।

अब लंबे स्पष्टीकरण के लिए ...


Xargs का उपयोग करते समय दो मुद्दों को ध्यान में रखना है:

  1. यह इनपुट को "तर्कों" में कैसे विभाजित करता है; तथा
  2. एक बार में बाल आदेश पारित करने के लिए कितने तर्क हैं।

Xargs के व्यवहार का परीक्षण करने के लिए, हमें एक उपयोगिता की आवश्यकता होती है जो यह दर्शाती है कि इसे कितनी बार निष्पादित किया जा रहा है और कितने तर्कों के साथ। मुझे नहीं पता कि ऐसा करने के लिए कोई मानक उपयोगिता है या नहीं, लेकिन हम इसे आसानी से बैश में कोड कर सकते हैं:

#!/bin/bash
echo -n "-> "; for a in "$@"; do echo -n "\"$a\" "; done; echo

मान लें कि आप इसे showअपनी वर्तमान निर्देशिका के रूप में सहेजते हैं और इसे निष्पादन योग्य बनाते हैं, यहां बताया गया है कि यह कैसे काम करता है:

$ ./show one two 'three and four'
-> "one" "two" "three and four" 

अब, यदि मूल प्रश्न वास्तव में बिंदु 2 के ऊपर है। ऊपर (जैसा कि मुझे लगता है कि यह कुछ ही समय में पढ़ने के बाद है), और इसे इस तरह से पढ़ना है (बोल्ड में परिवर्तन):

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

तो जवाब है -n 1

आइए xargs के डिफ़ॉल्ट व्यवहार की तुलना करें, जो व्हॉट्सएप के चारों ओर इनपुट को विभाजित करता है और कमांड को जितनी बार संभव हो सके कॉल करता है:

$ echo one two 'three and four' | xargs ./show 
-> "one" "two" "three" "and" "four" 

और इसके साथ व्यवहार -n 1:

$ echo one two 'three and four' | xargs -n 1 ./show 
-> "one" 
-> "two" 
-> "three" 
-> "and" 
-> "four" 

यदि, दूसरी ओर, मूल प्रश्न बिंदु 1 था। इनपुट विभाजन और इसे इस तरह से पढ़ा जाना था (यहां आने वाले कई लोगों को लगता है कि मामला है, या दो मुद्दों को भ्रमित कर रहे हैं)

मैं दिए गए इनपुट की प्रत्येक पंक्ति के लिए xargs को कमांड को बिल्कुल एक तर्क से कैसे निष्पादित कर सकता हूं ? इसका डिफ़ॉल्ट व्यवहार व्हाट्सएप के आसपास की लाइनों को चोक करना है

तब उत्तर अधिक सूक्ष्म होता है।

किसी को लगता है कि -L 1मदद की जा सकती है, लेकिन यह पता चला है कि यह तर्क पार्सिंग को नहीं बदलता है। यह प्रत्येक इनपुट लाइन के लिए केवल एक बार कमांड निष्पादित करता है, उस इनपुट लाइन पर जितने भी तर्क थे उतने ही हैं:

$ echo $'one\ntwo\nthree and four' | xargs -L 1 ./show 
-> "one" 
-> "two" 
-> "three" "and" "four" 

इतना ही नहीं, लेकिन अगर एक लाइन व्हॉट्सएप के साथ समाप्त होती है, तो इसे अगले में जोड़ा जाता है:

$ echo $'one \ntwo\nthree and four' | xargs -L 1 ./show 
-> "one" "two" 
-> "three" "and" "four" 

स्पष्ट रूप से, -Lxargs द्वारा इनपुट को तर्कों में विभाजित करने के तरीके को बदलने के बारे में नहीं है।

क्रॉस-प्लेटफ़ॉर्म फ़ैशन (GNU एक्सटेंशन को छोड़कर) में ऐसा करने वाला एकमात्र तर्क है -0, जो NUL बाइट्स के चारों ओर इनपुट को विभाजित करता है।

फिर, NUL की मदद से newlines का अनुवाद करने की बात है tr:

$ echo $'one \ntwo\nthree and four' | tr '\n' '\0' | xargs -0 ./show 
-> "one " "two" "three and four" 

अब तर्क पार्सिंग सब ठीक लग रहा है, जिसमें पीछे वाला व्हाट्सएप भी शामिल है।

अंत में, यदि आप इस तकनीक के साथ गठबंधन करते हैं, तो आपको -n 1इनपुट लाइन प्रति एक कमांड निष्पादन मिलता है, आपके पास जो भी इनपुट है, जो मूल प्रश्न को देखने का एक और तरीका हो सकता है (संभवतः सबसे सहज, शीर्षक दिया गया):

$ echo $'one \ntwo\nthree and four' | tr '\n' '\0' | xargs -0 -n1 ./show 
-> "one " 
-> "two" 
-> "three and four" 

ऐसा लगता है कि यह बेहतर उत्तर है। हालाँकि, मुझे अभी भी समझ में नहीं आया है कि -L और -n में क्या अंतर है ... क्या आप थोड़ा और समझा सकते हैं?
ओलाला

5
@olala -Lइनपुट लाइन के अनुसार एक बार कमांड निष्पादित करता है (लेकिन लाइन के अंत में एक स्थान इसे अगली लाइन में जोड़ता है , और लाइन अभी भी व्हाट्सएप के अनुसार तर्कों में विभाजित है); जबकि -nइनपुट तर्क के अनुसार एक बार कमांड निष्पादित करता है। यदि आप ->आउटपुट उदाहरणों की संख्या की गणना करते हैं, तो वे स्क्रिप्ट ./showनिष्पादित होने की संख्या है।
टोबिया

समझा! एक पंक्ति के अंत में एक स्थान का एहसास नहीं हुआ जो इसे अगली पंक्ति में जोड़ता है। धन्यवाद!
ओलाला

4
GNU के xargsपास उपयोगी एक्सटेंशन हो सकते हैं या नहीं भी हो सकते हैं जो आपको इसे दूर करने की अनुमति देते हैंtr । से xargs --help- -d, --delimiter = वर्ण इनपुट स्ट्रीम में आइटम, चरित्र से अलग होते हैं खाली स्थान के द्वारा नहीं; उद्धरण और बैकलैश प्रसंस्करण और तार्किक ईओएफ प्रसंस्करण को निष्क्रिय करता है
21:39 पर पॉट्र डोब्रोगोस्ट

इस उत्तर के बारे में उलझन में लगता है -L-Lप्रति पंक्ति स्क्रिप्ट को निष्पादित करने के लिए कितनी बार कहते हैं, यह नहीं कहता है कि एक समय में उपभोग करने के लिए इनपुट डेटा की कितनी लाइनें हैं।
Moberg

22

यदि आप आने वाली हर लाइन (यानी परिणाम) के लिए कमांड चलाना चाहते हैं find, तो आपको इसके लिए क्या चाहिए xargs?

प्रयत्न:

find अपने आदेश को पथ-type f -exec {} \;

जहाँ {}फ़ाइल नाम से शाब्दिक प्रतिस्थापित हो जाता है और यह जानने के \;लिए शाब्दिक की आवश्यकता होती findहै कि कस्टम कमांड वहाँ समाप्त होती है।

संपादित करें:

(अपने प्रश्न के संपादन के बाद स्पष्ट करें कि आप के बारे में जानते हैं -exec)

से man xargs:

-L अधिकतम-लाइनें
अधिकांश अधिकतम-रेखाएँ nonblank इनपुट लाइन प्रति कमांड लाइन पर उपयोग करें। अनुगामी रिक्तता के कारण इनपुट लाइन तार्किक रूप से अगली इनपुट लाइन पर जारी रहती है। इंप्लाइज -x।

ध्यान दें कि रिक्त स्थान पर समाप्त होने वाले फ़ाइलनामों का उपयोग करने पर आपको परेशानी होगी xargs:

$ mkdir /tmp/bax; cd /tmp/bax
$ touch a\  b c\  c
$ find . -type f -print | xargs -L1 wc -l
0 ./c
0 ./c
0 total
0 ./b
wc: ./a: No such file or directory

इसलिए यदि आप -execविकल्प के बारे में परवाह नहीं करते हैं , तो आप बेहतर उपयोग करते हैं -print0और -0:

$ find . -type f -print0 | xargs -0L1 wc -l
0 ./c
0 ./c
0 ./b
0 ./a

17

मैं दिए गए इनपुट की प्रत्येक पंक्ति के लिए एक बार ठीक से कमांड निष्पादित कैसे कर सकता हूं?

-L 1सरल समाधान है, लेकिन यह काम नहीं करता है अगर किसी भी फाइल में रिक्त स्थान होते हैं। यह खोज के -print0तर्क का एक महत्वपूर्ण कार्य है - व्हाट्सएप के बजाय '\ 0' वर्ण द्वारा तर्कों को अलग करना। यहाँ एक उदाहरण है:

echo "file with space.txt" | xargs -L 1 ls
ls: file: No such file or directory
ls: with: No such file or directory
ls: space.txt: No such file or directory

एक बेहतर समाधान है कि trन्यूलाइनों को अशक्त ( \0) वर्णों में बदलने के लिए उपयोग किया जाए और फिर xargs -0तर्क का उपयोग किया जाए । यहाँ एक उदाहरण है:

echo "file with space.txt" | tr '\n' '\0' | xargs -0 ls
file with space.txt

यदि आपको कॉल की संख्या को सीमित करने की आवश्यकता है तो आप -n 1प्रत्येक इनपुट के लिए प्रोग्राम में एक कॉल करने के लिए तर्क का उपयोग कर सकते हैं :

echo "file with space.txt" | tr '\n' '\0' | xargs -0 -n 1 ls

यह आपको ब्रेक में नल को बदलने से पहले खोज के आउटपुट को फ़िल्टर करने की भी अनुमति देता है।

find . -name \*.xml | grep -v /target/ | tr '\n' '\0' | xargs -0 tar -cf xml.tar

1
दूसरे कोड ब्लॉक tr '\ n' \ '0 \ => tr' \ n '' \ 0 '' में एक सिंटैक्स त्रुटि है, मैंने इसे ठीक करने की कोशिश की, लेकिन "संपादन कम से कम 6 वर्ण का होना चाहिए" (ऐसा लगता है बेवकूफ के रूप में करने के लिए मना कर दिया क्योंकि मेरे परिवर्तन 6 चार्ट से कम था)
htaccess

1
इसका क्या मतलब है: "उपयोग करने के साथ एक और समस्या -Lयह है कि यह प्रत्येक xargsकमांड कॉल के लिए कई तर्क नहीं देता है ।"
Moberg

मैंने उस विस्तृत जानकारी को हटाने के लिए अपने उत्तर में सुधार किया है @Moberg।
ग्रे


9

ये दो तरीके भी काम करते हैं, और अन्य कमांड के लिए काम करेंगे जो कि खोज का उपयोग नहीं कर रहे हैं!

xargs -I '{}' rm '{}'
xargs -i rm '{}'

उदाहरण के मामले का उपयोग करें:

find . -name "*.pyc" | xargs -i rm '{}'

इस निर्देशिका के तहत सभी pyc फ़ाइलों को हटा देगा भले ही pyc फ़ाइलों में स्थान हो।


यह हर तत्व के लिए एक उपयोगिता कॉल जारी करता है जो इष्टतम नहीं है।
ग्रे

7
find path -type f | xargs -L1 command 

आपको जो चाहिए वह यह है।


4

निम्न आदेश में सभी फ़ाइलों (-type f) को मिलेगा /pathऔर फिर उन्हें cpवर्तमान फ़ोल्डर का उपयोग करके कॉपी करें । कमांड लाइन -I %में एक प्लेसहोल्डर वर्ण निर्दिष्ट करने के लिए उपयोग पर ध्यान दें cpताकि फ़ाइल नाम के बाद तर्क रखे जा सकें।

find /path -type f -print0 | xargs -0 -I % cp % .

एक्सएआरजीएस (जीएनयू फाउंड्यूटिल्स) 4.4.0 के साथ परीक्षण किया गया


2

आप क्रमशः --मैक्स-लाइन्स या --मैक्स-आर्ग्स झंडे का उपयोग करके लाइनों की संख्या, या तर्क (यदि प्रत्येक तर्क के बीच रिक्त स्थान हैं) को सीमित कर सकते हैं।

  -L max-lines
         Use at most max-lines nonblank input lines per command line.  Trailing blanks cause an input line to be logically continued on the next  input
         line.  Implies -x.

  --max-lines[=max-lines], -l[max-lines]
         Synonym  for  the -L option.  Unlike -L, the max-lines argument is optional.  If max-args is not specified, it defaults to one.  The -l option
         is deprecated since the POSIX standard specifies -L instead.

  --max-args=max-args, -n max-args
         Use at most max-args arguments per command line.  Fewer than max-args arguments will be used if the size (see  the  -s  option)  is  exceeded,
         unless the -x option is given, in which case xargs will exit.

0

ऐसा लगता है कि टोबिया के उत्तर के लिए एक टिप्पणी जोड़ने के लिए मेरे पास पर्याप्त प्रतिष्ठा नहीं है , इसलिए मैं इस "उत्तर" को जोड़ रहा हूं ताकि हम में xargsसे एक को विंडोज प्लेटफॉर्म पर उसी तरह प्रयोग करने में मदद मिल सके ।

यहाँ एक विंडोज़ बैच फ़ाइल है जो टोबिया के कोडेड "शो" स्क्रिप्ट के समान काम करती है:

@echo off
REM
REM  cool trick of using "set" to echo without new line
REM  (from:  http://www.psteiner.com/2012/05/windows-batch-echo-without-new-line.html)
REM
if "%~1" == "" (
    exit /b
)

<nul set /p=Args:  "%~1"
shift

:start
if not "%~1" == "" (
    <nul set /p=, "%~1"
    shift
    goto start
)
echo.

0

@Draemon जवाब फ़ाइल में स्थान के साथ "-0" के साथ सही लगता है।

मैं xargs कमांड आज़मा रहा था और मैंने पाया कि "-0" पूरी तरह से "-L" के साथ काम करता है। यहां तक ​​कि रिक्त स्थान का इलाज किया जाता है (यदि इनपुट शून्य समाप्त हो गया था)। निम्नलिखित एक उदाहरण है :

#touch "file with space"
#touch "file1"
#touch "file2"

निम्नलिखित सूची में प्रत्येक तर्क पर nulls को विभाजित करेगा और कमांड निष्पादित करेगा:

 #find . -name 'file*' -print0 | xargs -0 -L1
./file with space
./file1
./file2

इसलिए -L1यदि "-0" के साथ प्रयोग किया जाता है, तो प्रत्येक अशक्त वर्ण पर तर्क निष्पादित किया जाएगा। अंतर देखने के लिए प्रयास करें:

 #find . -name 'file*' -print0 | xargs -0 | xargs -L1
 ./file with space ./file1 ./file2

यहां तक ​​कि यह एक बार निष्पादित होगा:

 #find . -name 'file*' -print0  | xargs -0  | xargs -0 -L1
./file with space ./file1 ./file2

एक बार "-L" के रूप में कमांड निष्पादित हो जाएगा अब null बाइट पर विभाजित नहीं होता है। आपको काम करने के लिए "-0" और "-L" दोनों प्रदान करने की आवश्यकता है।


-3

आपके उदाहरण में, xargs में खोज के आउटपुट को पाइप करने का मुद्दा यह है कि खोज के -exec विकल्प का मानक व्यवहार प्रत्येक मिली फ़ाइल के लिए एक बार कमांड निष्पादित करना है। यदि आप खोज का उपयोग कर रहे हैं, और आप इसका मानक व्यवहार चाहते हैं, तो उत्तर सरल है - आरंभ करने के लिए xargs का उपयोग न करें।


वास्तव में, मैं क्या कर सकते हैं मतलब ओपी के संपादन से कि इनपुट डेटा के साथ कुछ नहीं करना है find, और यही वजह है कि वे पसंद नहीं करते -execविकल्प।
tzot 16:24

-3

मौजूदा या उप-फ़ोल्डर पर हर बिल्ड.xml पर चींटी कार्य को साफ करें।

find . -name 'build.xml' -exec ant -f {} clean-all \;

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