अगर स्टड इनपुट खाली है तो xargs कमांड को कैसे अनदेखा करें?


189

इस आदेश पर विचार करें:

ls /mydir/*.txt | xargs chown root

इरादा सभी पाठ फ़ाइलों के मालिकों mydirको रूट में बदलने का है

मुद्दा यह है कि अगर कोई .txtफ़ाइल नहीं है, mydirतो xargs यह कहते हुए एक त्रुटि करता है कि कोई पथ निर्दिष्ट नहीं है। यह एक हानिरहित उदाहरण है क्योंकि एक त्रुटि डाली जा रही है, लेकिन कुछ मामलों में, जैसे स्क्रिप्ट में जिसे मुझे यहां उपयोग करने की आवश्यकता है, एक खाली पथ को वर्तमान निर्देशिका माना जाता है। इसलिए अगर मैं उस कमांड को चलाता हूं /home/tom/तो यदि कोई परिणाम नहीं है ls /mydir/*.txtऔर सभी फाइलों /home/tom/को उनके मालिकों ने रूट में बदल दिया है।

तो मैं xargs को खाली परिणाम की अनदेखी कैसे कर सकता हूं?


6
एक तरफ: lsप्रोग्रामेटिक उपयोग के लिए कभी भी पाइप आउटपुट नहीं ; देख mywiki.wooledge.org/ParsingLs
चार्ल्स डफी

मेरा उपयोग मामला है git branch --merged | grep -v '^* ' | xargs git branch -d, जो खाली इनपुट पर भी विफल रहता है
belkaka

जवाबों:


305

GNU के लिए xargs, आप -rया --no-run-if-emptyविकल्प का उपयोग कर सकते हैं :

--no-run-if-empty
-r
यदि मानक इनपुट में कोई भी गैर-फ़िल्टर नहीं है, तो कमांड न चलाएँ। सामान्यतया, इनपुट न होने पर भी कमांड एक बार चलाया जाता है। यह विकल्प GNU एक्सटेंशन है।


9
मैंने ईमानदारी से पहले Google में खोज की और यह पाया (लेकिन मैनुअल पढ़े बिना नहीं पूछा होगा)। मुझे लगा कि यह होड डिफ़ॉल्ट व्यवहार है, इसे सक्षम करने के लिए स्विच की आवश्यकता नहीं है।
जॉनीजेड

28
दुर्भाग्य से यह एक मैक पर काम नहीं करता है। न तो छोटा और न ही लंबा विकल्प।
वेदी

9
@wedi - OSX में BSD यूजरस्पेस है, इसलिए इस तरह की बात अक्सर होगी। आप GNU फाइलुटील्स को स्थापित करने के लिए होमब्रे का उपयोग करके इसके चारों ओर काम कर सकते हैं।
edk750

7
आपका मतलब है brew install findutilsfindutils, नहीं fileutils
मैटर

3
MacOS पर, वैसे भी कमांड नहीं चलाने पर ध्वज परिणाम प्रदान नहीं करता है, इसलिए मुझे लगता है कि इसकी आवश्यकता नहीं है।
तर्जुक

15

गैर जीएनयू xargs के उपयोगकर्ताओं का लाभ उठा सकते -L <#lines>, -n <#args>, -i, और -I <string>:

ls /empty_dir/ | xargs -n10 chown root # chown executed every 10 args or fewer
ls /empty_dir/ | xargs -L10 chown root # chown executed every 10 lines or fewer
ls /empty_dir/ | xargs -i cp {} {}.bak # every {} is replaced with the args from one input line
ls /empty_dir/ | xargs -I ARG cp ARG ARG.bak # like -i, with a user-specified placeholder

ध्यान रखें कि xargs व्हाट्सएप पर लाइन को विभाजित करता है लेकिन उद्धृत और भागने उपलब्ध हैं; विवरण के लिए RTFM।

इसके अलावा, डोरोन बेहार का उल्लेख है, यह समाधान पोर्टेबल नहीं है, इसलिए चेक की आवश्यकता हो सकती है:

$ uname -is
SunOS sun4v
$ xargs -n1 echo blah < /dev/null
$ uname -is
Linux x86_64
$ xargs --version | head -1
xargs (GNU findutils) 4.7.0-git
$ xargs -n1 echo blah < /dev/null
blah

2
प्रश्न का उत्तर नहीं लगता है?
निकोलस राउल

2
@ निकोलस: यह निष्पादन को रोकने का तरीका है यदि आपका संस्करण स्विच का xargsसमर्थन नहीं करता है --no-run-if-emptyऔर एसटीडीआईएन इनपुट के बिना कमांड तर्क को चलाने का प्रयास करता है (यह सोलारिस 10 में मामला है)। अन्य यूनिक्स में संस्करण सिर्फ एक खाली सूची (जैसे AIX) को अनदेखा कर सकते हैं।
एरियलको जूल

4
हाँ! मैक OSX पर, echo '' | xargs -n1 echo blahकुछ भी नहीं करता है; जबकि echo 'x' | xargs -n1 echo blahप्रिंट "ब्लाह"।
कार्लासमयम

2
GNU और BSD / OSX दोनों के लिए समर्थन मैं कुछ इस तरह का उपयोग करके समाप्त करता हूं: ls /mydir/*.txt | xargs -n 1 -I {} chown root {}जैसा कि यह उत्तर बताता है।
लुइयां बियानचिन

3
यह ध्यान दिया जाना चाहिए कि GNU के साथ echo '' | xargs -n1 echo blahप्रिंट blahकरता है xargs
डोरोन बेहार

11

man xargsकहता है --no-run-if-empty


1
यदि आप OSX पर हैं तो यह नहीं होगा। edk750 ने अपनी टिप्पणी में यह समझाया है कि यदि आप उत्सुक हैं कि क्यों।
जस्सोनलहार्ड २ 27'१on

9

के संदर्भ में xargs, आप -rसुझाव के अनुसार उपयोग कर सकते हैं , हालांकि यह बीएसडी द्वारा समर्थित नहीं है xargs

उदाहरण के लिए, आप कुछ अतिरिक्त अस्थायी फ़ाइल पास कर सकते हैं:

find /mydir -type f -name "*.txt" -print0 | xargs -0 chown root $(mktemp)

या अपने stderr को null में पुनर्निर्देशित करें ( 2> /dev/null), जैसे

find /mydir -type f -name "*.txt" -print0 | xargs -0 chown root 2> /dev/null || true

एक और बेहतर तरीका यह है कि whileलूप का उपयोग करके मिली फ़ाइलों पर पुनरावृति की जाए :

find /mydir -type f -name "*.txt" -print0 | while IFS= read -r -d '' file; do
  chown -v root "$file"
done

इसे भी देखें: Mac OS X में xargs के खाली परिणामों पर ध्यान न दें


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

इसलिए आपको अपना दृष्टिकोण बदलना चाहिए और findइसके बजाय कमांड का उपयोग करना चाहिए , जैसे

find /mydir -type f -name "*.txt" -execdir chown root {} ';'

1
क्षमा करें, मुझे समझ नहीं आया कि यह कैसे while IFS= read -r -d '' fileमान्य है। क्या तुम समझा सकते हो?
एड्रियन

2

OSX पर: तर्क से xargsनिपटने के लिए बैश को लागू करें -r, जैसे कि $HOME/binइसे अंदर डालें और इसे इसमें जोड़ें PATH:

#!/bin/bash
stdin=$(cat <&0)
if [[ $1 == "-r" ]] || [[ $1 == "--no-run-if-empty" ]]
then
    # shift the arguments to get rid of the "-r" that is not valid on OSX
    shift
    # wc -l return some whitespaces, let's get rid of them with tr
    linecount=$(echo $stdin | grep -v "^$" | wc -l | tr -d '[:space:]') 
    if [ "x$linecount" = "x0" ]
    then
      exit 0
    fi
fi

# grep returns an error code for no matching lines, so only activate error checks from here
set -e
set -o pipefail
echo $stdin | /usr/bin/xargs $@

2

यह GNU xargs का एक व्यवहार है जिसे -r, --no-run-if-blank के उपयोग से दबाया जा सकता है।

Xargs के * BSD वेरिएंट में डिफ़ॉल्ट रूप से यह व्यवहार है, इसलिए -r की जरूरत नहीं है। चूंकि FreeBSD 7.1 (जनवरी 2009 में जारी किया गया है) -एक तर्क को स्वीकार किया जाता है (डायन कुछ भी नहीं करता है)।

मैं व्यक्तिगत रूप से स्क्रिप्ट में लॉन्गोप्ट का उपयोग करना पसंद करता हूं, लेकिन चूंकि * बीएसडी xargs केवल "-r" का उपयोग नहीं करता है और xargs * बीएसडी ऑन लाइन सिस्टम पर समान कार्य करेगा।

MacOS पर xargs (वर्तमान में MacOS Mojave) दुखद रूप से "-r" तर्क का समर्थन नहीं करता है।

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