कई आदेशों के साथ -exec खोजें


429

मैं बिना किसी सफलता के कई आदेशों के साथ खोज-उपयोग करने की कोशिश कर रहा हूं। क्या किसी को पता है कि निम्नलिखित जैसे कमांड संभव हैं?

find *.txt -exec echo "$(tail -1 '{}'),$(ls '{}')" \;

मूल रूप से, मैं वर्तमान निर्देशिका में प्रत्येक txt फ़ाइल की अंतिम पंक्ति को प्रिंट करने और लाइन के अंत में प्रिंट करने की कोशिश कर रहा हूं, फ़ाइल नाम के बाद एक अल्पविराम।



1
जहाँ तक कमांड की संभावना के लिए जाँच करने की बात है, क्या आपने इसे अपने सिस्टम पर आज़माया नहीं है?
श्रीराम

1
से findमैन्युअल पृष्ठ: There are unavoidable security problems surrounding use of the -exec option; you should use the -execdir option instead.unixhelp.ed.ac.uk/CGI/man-cgi?find
JVE999


@ JVE999 लिंक टूट गया है, वैकल्पिक ss64.com/bash/find.html
कीथ एम

जवाबों:


658

find-execआदेश में कई भागों को स्वीकार करता है । उदाहरण के लिए:

find . -name "*.txt" -exec echo {} \; -exec grep banana {} \;

ध्यान दें कि इस मामले में दूसरी कमांड केवल तभी चलेगी जब पहले वाला सफलतापूर्वक लौटता है, जैसा कि @ कैलेब द्वारा बताया गया है। यदि आप चाहते हैं कि दोनों कमांड उनकी सफलता या विफलता की परवाह किए बिना चलें, तो आप इस निर्माण का उपयोग कर सकते हैं:

find . -name "*.txt" \( -exec echo {} \; -o -exec true \; \) -exec grep banana {} \;

दो बार grep कैसे करें? यह विफल हो रहा है: खोज करें ।/* -exec grep -v 'COLD,' {} \; -exec egrep -i "my_string" {} \;
राजीव

51
@rajeev दूसरा रिटर्न केवल तभी चलेगा जब पहले रिटर्न की सफलता के लिए रिटर्न कोड, अन्यथा इसे छोड़ दिया जाएगा। यह शायद इस जवाब में ध्यान दिया जाना चाहिए।
कालेब

1
इसका जवाब होगा
pylover

1
-nइको द्वारा उत्पन्न नई लाइन को दबाने के लिए कुछ अन्य उत्तरों में उपयोग पर ध्यान दें , जो कि आसान है यदि आपकी दूसरी कमांड केवल एक लाइन आउटपुट का उत्पादन करती है और आप चाहते हैं कि उन्हें पढ़ना आसान हो।
विलियम टरेल

महान समाधान। एक जादू की तरह काम करता है।
फिलिप डेल्टिल

98
find . -type d -exec sh -c "echo -n {}; echo -n ' x '; echo {}" \;

3
आप बैश चलाना चाहते हैं तो बजाय बॉर्न की आप भी उपयोग कर सकते हैं ... -exec bash -c ...के बजाय ... -exec sh -c ...
केनी एविट

9
{}शेल कोड में कभी भी एम्बेड न करें । देखें unix.stackexchange.com/questions/156008/…
कुसलानंद

3
+1 @ कुसलानंद इंजेक्शन का नाम नाजुक और असुरक्षित है। मापदंडों का उपयोग करें। देख SC2156
pambda

52

निम्न में से एक:

find *.txt -exec awk 'END {print $0 "," FILENAME}' {} \;

find *.txt -exec sh -c 'echo "$(tail -n 1 "$1"),$1"' _ {} \;

find *.txt -exec sh -c 'echo "$(sed -n "\$p" "$1"),$1"' _ {} \;

12
{} से पहले अंडरस्कोर क्या है?
qed

2
@qed: यह एक फेंक-दूर मूल्य है जो की जगह रखता है $0। "_" के बजाय "फोब्बर" के साथ इसे आज़माएं: find /usr/bin -name find -exec sh -c 'echo "[$0] [$1]"' foobar {} \;- आउटपुट: "[फ़ॉबोर] [/ usr / bin / find]"।
अगली सूचना तक रोक दिया गया।

1
@XuWang: हां, मैं कहूंगा कि ऐसा ही है। जैसा कि आप जानते हैं, $0आमतौर पर कार्यक्रम का नाम ( ARGV[0]) है।
अगली सूचना तक रोक दिया गया।

3
यह महत्वपूर्ण है, इस विधि के लिए, कि जो स्क्रिप्ट पास की गई sh -cहै, वह सिंगल कोट्स में है, डबल नहीं। अन्यथा $1गलत दायरे में है।
निक

1
@ निक कोट्स का इससे कोई लेना-देना नहीं है - '$1'जब तक आप वैरिएबल ( "\$1") से बच जाते हैं, तब तक आप डबल कोट्स के साथ लिख सकते हैं । आप अन्य पात्रों से भी बच सकते हैं ( "\"")।
कैमिलो मार्टिन

22

एक और तरीका इस तरह है:

multiple_cmd() { 
    tail -n1 $1; 
    ls $1 
}; 
export -f multiple_cmd; 
find *.txt -exec bash -c 'multiple_cmd "$0"' {} \;

एक पंक्ति में

multiple_cmd() { tail -1 $1; ls $1 }; export -f multiple_cmd; find *.txt -exec bash -c 'multiple_cmd "$0"' {} \;
  • " multiple_cmd()" - एक फ़ंक्शन है
  • " export -f multiple_cmd-" इसे निर्यात करेगा ताकि कोई अन्य उपधारा इसे देख सके
  • " find *.txt -exec bash -c 'multiple_cmd "$0"' {} \;" - पाते हैं कि आपके उदाहरण पर फ़ंक्शन निष्पादित करेगा

इस तरह से multiple_cmd आपकी जरूरत के अनुसार लंबा और जटिल हो सकता है।

उम्मीद है की यह मदद करेगा।


एकदम सही, मैं क्या जरूरत है!
एंथ्रोपिक

OSX पर मेरे लिए काम नहीं करता है
थॉमस

@ थोमस यह करता है, लेकिन इस एक लाइनर की कोशिश करता है, जो ऑक्स में परीक्षण किया गया है। मैंने वहां कुछ फाइलों / डायरियों के साथ 'आआ' नाम की एक निर्देशिका बनाई और उसमें सीडीडी। फिर, ~/aaa$ acmd() { echo x \"$1\" x; }; export -f acmd; find . -exec bash -c 'acmd {}' \;
बारलोप

@barlop, मैं कोशिश करूँगा कि; धन्यवाद!
थॉमस

14

एक आसान तरीका है:

find ... | while read -r file; do
    echo "look at my $file, my $file is amazing";
done

वैकल्पिक रूप से:

while read -r file; do
    echo "look at my $file, my $file is amazing";
done <<< "$(find ...)"

1
फ़ाइल नाम उन में नए हो सकते हैं, यही कारण है कि -प्रिंट0 तर्क है और xargs का -0 तर्क है
abasterfield

@abasterfield मुझे हमेशा उम्मीद है कि जंगली लोल में उन लोगों को कभी नहीं पाऊंगा
कैमिलो मार्टिन

1
मैं जो करना चाहता था, वह "मिल गया ... -exec zcat {} | wc -l \;" जो काम नहीं किया। हालाँकि, खोजें ... | जबकि -r फ़ाइल पढ़ें; गूंज "$ फ़ाइल: zcat $file | wc -l"; किया काम करता है, इसलिए धन्यवाद!
ग्रेग डफ़र्टी

ऊपर टिप्पणी में मेरे पास "zcat $ file | wc -l" के आसपास "बैक टिक्स" है। दुर्भाग्य से एसओ उन लोगों को फॉर्मेटिंग में बदल देता है, इसलिए मैंने इसे एक वास्तविक उत्तर के रूप में जोड़ा है जिसमें सही कोड दिखाई दे रहा है
ग्रेग डौगर्टी

1
@GregDougherty आप बैकस्टिक्स से बचने के `लिए ऐसा कर सकते हैं कि आप बैकस्लैश का उपयोग करते हैं जैसे: \​`(फिर भी, इसका उपयोग करने का एक और अच्छा कारण है $())।
कैमिलो मार्टिन

8

मुझे नहीं पता कि क्या आप इसे खोज के साथ कर सकते हैं, लेकिन एक वैकल्पिक समाधान शेल स्क्रिप्ट बनाने और इसे खोजने के साथ चलाने के लिए होगा।

lastline.sh:

echo $(tail -1 $1),$1

स्क्रिप्ट को निष्पादन योग्य बनाएं

chmod +x lastline.sh

उपयोग करें find:

find . -name "*.txt" -exec ./lastline.sh {} \;

7
बैकटिक्स को हटा दिया गया है, कृपया $ (...) के उपयोग को प्रोत्साहित करें जो बेहतर पठनीय है, फ़ॉन्टडाईपेन्डली और घोंसले के लिए आसान है। धन्यवाद।
उपयोगकर्ता अज्ञात

4

डेनिस का 1 जवाब मुसीबत को हल करने का जवाब है। लेकिन वास्तव में यह केवल शीर्षक के सुझाव की तरह एक निष्पादन में कई आदेशों के साथ एक खोज नहीं है। कई आज्ञाओं के साथ एक अमल का जवाब देने के लिए हमें किसी और को फिर से शुरू करने के लिए देखना होगा। यहाँ एक उदाहरण है:

.Log फ़ाइलों की अंतिम 10000 पंक्तियों को रखें, जिन्हें पिछले 7 दिनों में 1 {} कमांड का उपयोग करके क्रांतिकारियों {} संदर्भों का उपयोग करके संशोधित किया गया है

1) देखें कि कमांड किस फाइल पर करेगी:

find / -name "*.log" -a -type f -a -mtime -7 -exec sh -c "echo tail -10000 {} \> fictmp; echo cat fictmp \> {} " \;

2) ऐसा करें: (नोट नहीं ""> "लेकिन केवल"> "यह चाहता है)

find / -name "*.log" -a -type f -a -mtime -7 -exec sh -c "tail -10000 {} > fictmp; cat fictmp > {} ; rm fictmp" \;


लेकिन यह टूट जाएगा अगर किसी एक फ़ाइलनाम में एक जगह है, मुझे विश्वास है।
कैमिलो मार्टिन

4

कैमिलो मार्टिन के लिए धन्यवाद, मैं एक संबंधित प्रश्न का उत्तर देने में सक्षम था:

मैं जो करना चाहता था

find ... -exec zcat {} | wc -l \;

जो काम नहीं किया। तथापि,

find ... | while read -r file; do echo "$file: `zcat $file | wc -l`"; done

काम करता है, इसलिए धन्यवाद!


2

@ टिंकर के उत्तर का विस्तार,

मेरे मामले में, मुझे एक निश्चित पाठ वाली फ़ाइलों में फ़ाइल नाम और पाए गए पाठ दोनों को प्रिंट करने command | command | commandके -execलिए अंदर करने की आवश्यकता थी ।

मैं इसके साथ करने में सक्षम था:

find . -name config -type f \( -exec  grep "bitbucket" {} \; -a -exec echo {} \;  \) 

परिणाम है:

    url = git@bitbucket.org:a/a.git
./a/.git/config
    url = git@bitbucket.org:b/b.git
./b/.git/config
    url = git@bitbucket.org:c/c.git
./c/.git/config

1
आप एक पैरामीटर पर कमांड के /dev/nullदूसरे तर्क के रूप में एक लाइन पर फ़ाइल नाम और grep'd सामग्री भी मुद्रित कर सकते हैं :grep-execfind . -name config -type f -exec grep "bitbucket" {} /dev/null \;
बिल फेट

1

xargs का उपयोग करना चाहिए :)

find *.txt -type f -exec tail -1 {} \; | xargs -ICONSTANT echo $(pwd),CONSTANT

एक और एक (osx पर काम कर रहा है)

find *.txt -type f -exec echo ,$(PWD) {} + -exec tail -1 {} + | tr ' ' '/'

3
यह उन findस्थितियों के लिए एक प्रमुख उपयोग के मामले को अनदेखा करता है जहां कमांड लाइन के लिए मिलान फ़ाइलों की संख्या बहुत बड़ी है। -execइस सीमा के आसपास जाने का एक तरीका है। एक उपयोगिता के लिए बाहर निकलने से लाभ होता है।
क्रिस जॉनसन

xargs -nप्रति आह्वान में मैचों की संख्या चुनने के लिए मौजूद है। हर मैच के लिए xargs -n 1 foocmdनिष्पादित करेगा foocmd {}
एंड्रयूएफ

0

एक find+xargsजवाब।

नीचे दिया गया उदाहरण सभी को मिल जाता है .html फाइलों को और .BAKसंलग्न एक्सटेंशन (जैसे 1.html> 1.html.BAK) के साथ एक प्रति बनाता है ।

कई प्लेसहोल्डर्स के साथ सिंगल कमांड

find . -iname "*.html" -print0 | xargs -0 -I {} cp -- "{}" "{}.BAK"

कई प्लेसहोल्डर्स के साथ कई कमांड

find . -iname "*.html" -print0 | xargs -0 -I {} echo "cp -- {} {}.BAK ; echo {} >> /tmp/log.txt" | sh

# if you need to do anything bash-specific then pipe to bash instead of sh

यह कमांड उन फ़ाइलों के साथ भी काम करेगी जो एक हाइफ़न से शुरू होती हैं या इसमें रिक्तियाँ होती हैं जैसे कि -my file.htmlपैरामीटर को कोट करने के लिए धन्यवाद और उसके --बाद cpसंकेतcp मापदंडों के अंत और वास्तविक फ़ाइल नामों की शुरुआत के लिए ।

-print0 नल-बाइट टर्मिनेटर के साथ परिणामों को पाइप करता है।


के लिए xargs-I {} पैरामीटर को परिभाषित करता है {}प्लेसहोल्डर के रूप में; आप जिसे भी चाहें प्लेसहोल्डर का उपयोग कर सकते हैं; -0इंगित करता है कि इनपुट आइटम अशक्त हैं।

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