यह उत्तर निम्नलिखित भागों में आता है:
- का मूल उपयोग
-exec
- के
-execसाथ संयोजन में उपयोग करनाsh -c
- का उपयोग करते हुए
-exec ... {} +
- का उपयोग करते हुए
-execdir
का मूल उपयोग -exec
-execविकल्प अपने तर्क के रूप में वैकल्पिक तर्क के साथ एक बाहरी उपयोगिता लेता है और यह निष्पादित करता है।
यदि {}दिए गए कमांड में कहीं भी स्ट्रिंग मौजूद है, तो इसके प्रत्येक उदाहरण को वर्तमान में संसाधित किए जा रहे पथनाम से बदल दिया जाएगा (जैसे ./some/path/FILENAME)। अधिकांश गोले में, दो पात्रों {}को उद्धृत करने की आवश्यकता नहीं है।
यह कहाँ समाप्त होता है, यह जानने के ;लिए कमांड को समाप्त करने की आवश्यकता है find। ;शेल से बचाने के लिए , इसे उद्धृत किया जाना चाहिए \;या ';', अन्यथा शेल इसे findकमांड के अंत के रूप में देखेगा ।
उदाहरण ( \पहली दो पंक्तियों के अंत में सिर्फ पंक्ति निरंतरता के लिए हैं):
find . -type f -name '*.txt' \
-exec grep -q 'hello' {} ';' \
-exec cat {} ';'
यह सभी नियमित फ़ाइलें ( -type f) पाएंगे जिनके नाम *.txtमौजूदा निर्देशिका में या उससे नीचे के पैटर्न से मेल खाते हैं । यह तब परीक्षण करेगा कि क्या स्ट्रिंग helloका उपयोग की गई किसी भी फ़ाइल में होता है grep -q(जो किसी भी आउटपुट का उत्पादन नहीं करता है, बस एक निकास स्थिति है)। उन फ़ाइलों के लिए जिनमें स्ट्रिंग होती है, catउन्हें फ़ाइल की सामग्री को टर्मिनल में आउटपुट करने के लिए निष्पादित किया जाएगा।
प्रत्येक -execभी find, जैसे पाया जाता है -typeऔर -nameकरता है , वैसे पथनामों पर एक "परीक्षण" की तरह कार्य करता है। यदि कमांड शून्य निकास स्थिति ("सफलता" को दर्शाता है) लौटाता है, तो findकमांड का अगला भाग माना जाता है, अन्यथा findकमांड अगले पथनाम के साथ जारी रहता है। इसका उपयोग उपरोक्त उदाहरण में उन फ़ाइलों को खोजने के लिए किया जाता है जिनमें स्ट्रिंग होती है hello, लेकिन अन्य सभी फ़ाइलों को अनदेखा करने के लिए।
उपरोक्त उदाहरण दो सबसे आम उपयोग मामलों को दिखाता है -exec:
- खोज को और प्रतिबंधित करने के लिए परीक्षण के रूप में।
- पाया पथनाम पर किसी प्रकार की कार्रवाई करने के लिए (आमतौर पर, लेकिन जरूरी नहीं,
findकमांड के अंत में )।
के -execसाथ संयोजन में उपयोग करनाsh -c
कमांड जो -execनिष्पादित कर सकता है वह वैकल्पिक तर्कों के साथ एक बाहरी उपयोगिता तक सीमित है। शेल-इन का उपयोग करने के लिए, फ़ंक्शंस, सशर्त, पाइपलाइन, पुनर्निर्देशन आदि के साथ सीधे -execसंभव नहीं है, जब तक कि sh -cबच्चे के शेल की तरह किसी चीज़ में लपेटा न जाए ।
यदि bashसुविधाएँ आवश्यक हैं, तो इसके bash -cस्थान पर उपयोग करें sh -c।
sh -c/bin/shकमांड लाइन पर दी गई स्क्रिप्ट के साथ चलता है , उसके बाद उस स्क्रिप्ट पर वैकल्पिक कमांड लाइन तर्क देता है।
sh -cबिना, स्वयं के उपयोग का एक सरल उदाहरण find:
sh -c 'echo "You gave me $1, thanks!"' sh "apples"
यह चाइल्ड शेल स्क्रिप्ट के दो तर्क देता है:
स्ट्रिंग sh। यह $0स्क्रिप्ट के अंदर उपलब्ध होगा , और यदि आंतरिक शेल एक त्रुटि संदेश का उत्पादन करता है, तो यह इस स्ट्रिंग के साथ उपसर्ग करेगा।
तर्क स्क्रिप्ट के applesरूप $1में उपलब्ध है , और अधिक तर्क थे, तब ये उपलब्ध होंगे $2, $3आदि। वे सूची में भी उपलब्ध होंगे "$@"(इसके अलावा $0जो हिस्सा नहीं होगा "$@")।
यह संयोजन के -execरूप में उपयोगी है क्योंकि यह हमें मनमाने ढंग से जटिल स्क्रिप्ट बनाने की अनुमति देता है जो इसके द्वारा प्राप्त पथनामों पर कार्य करता है find।
उदाहरण: उन सभी नियमित फ़ाइलों को खोजें जिनमें एक निश्चित फ़ाइल नाम प्रत्यय है, और उस फ़ाइल नाम के प्रत्यय को कुछ अन्य प्रत्यय में बदल दें, जहां प्रत्यय चर में रखे गए हैं:
from=text # Find files that have names like something.text
to=txt # Change the .text suffix to .txt
find . -type f -name "*.$from" -exec sh -c 'mv "$3" "${3%.$1}.$2"' sh "$from" "$to" {} ';'
आंतरिक स्क्रिप्ट के अंदर, $1स्ट्रिंग होगा text, $2स्ट्रिंग होगा txtऔर $3जो भी पथ नाम होगा findहमारे लिए मिल गया है। पैरामीटर विस्तार ${3%.$1}पाथनाम लेगा और इससे प्रत्यय हटा .textदेगा।
या, का उपयोग कर dirname/ basename:
find . -type f -name "*.$from" -exec sh -c '
mv "$3" "$(dirname "$3")/$(basename "$3" ".$1").$2"' sh "$from" "$to" {} ';'
या, आंतरिक स्क्रिप्ट में जोड़े गए चर के साथ:
find . -type f -name "*.$from" -exec sh -c '
from=$1; to=$2; pathname=$3
mv "$pathname" "$(dirname "$pathname")/$(basename "$pathname" ".$from").$to"' sh "$from" "$to" {} ';'
ध्यान दें कि इस अंतिम भिन्नता में, वैरिएबल fromऔर toचाइल्ड शेल में बाहरी स्क्रिप्ट में समान नामों वाले वेरिएबल्स से अलग हैं।
ऊपर से एक मनमाना जटिल स्क्रिप्ट बुला का सही तरीका है -execके साथ find। findजैसे लूप में उपयोग करना
for pathname in $( find ... ); do
त्रुटि प्रवण और अयोग्य (व्यक्तिगत राय) है। यह व्हॉट्सएप पर फ़ाइल नाम को विभाजित कर रहा है, फ़ाइल नाम ग्लोबिंग को आमंत्रित करता है, और शेल findके पहले पुनरावृत्ति को चलाने से पहले शेल के पूर्ण परिणाम का विस्तार करने के लिए शेल को भी मजबूर करता है ।
यह सभी देखें:
का उपयोग करते हुए -exec ... {} +
;अंत में द्वारा बदले जा सकते +। यह findदिए गए कमांड को प्रत्येक पाए गए पथनाम के लिए एक बार के बजाय संभव के रूप में कई तर्कों (पाथनाम) के साथ निष्पादित करने का कारण बनता है। इसके लिए कार्य करने {} से ठीक पहले तार को होना होता है+ ।
find . -type f -name '*.txt' \
-exec grep -q 'hello' {} ';' \
-exec cat {} +
यहाँ, findपरिणामी मार्ग एकत्र करेगा और catएक ही बार में उनमें से कई को निष्पादित करेगा।
find . -type f -name "*.txt" \
-exec grep -q "hello" {} ';' \
-exec mv -t /tmp/files_with_hello/ {} +
इसी तरह, mvजितना संभव हो उतना कम बार निष्पादित किया जाएगा। इस अंतिम उदाहरण के लिए mvकोर्यूटिल्स (जो -tविकल्प का समर्थन करता है) से जीएनयू की आवश्यकता होती है ।
का उपयोग करना -exec sh -c ... {} +भी एक कुशल तरीके से एक जटिल स्क्रिप्ट के साथ पाथनाम के सेट पर लूप करने के लिए है।
उपयोग करते समय मूल बातें समान हैं -exec sh -c ... {} ';', लेकिन स्क्रिप्ट अब तर्कों की एक लंबी सूची लेती है। इनको "$@"स्क्रिप्ट के अंदर लूपिंग करके ओवर किया जा सकता है ।
फ़ाइल नाम प्रत्ययों को बदलने वाले अंतिम खंड से हमारा उदाहरण:
from=text # Find files that have names like something.text
to=txt # Change the .text suffix to .txt
find . -type f -name "*.$from" -exec sh -c '
from=$1; to=$2
shift 2 # remove the first two arguments from the list
# because in this case these are *not* pathnames
# given to us by find
for pathname do # or: for pathname in "$@"; do
mv "$pathname" "${pathname%.$from}.$to"
done' sh "$from" "$to" {} +
का उपयोग करते हुए -execdir
वहाँ भी है -execdir(ज्यादातर findवेरिएंट द्वारा लागू किया गया है , लेकिन एक मानक विकल्प नहीं है)।
इस तरह काम करता है -execअंतर यह है कि दिए गए शेल कमांड अपने वर्तमान कार्यशील निर्देशिका के रूप में पाया पथ नाम की सूची के साथ क्रियान्वित किया जाता है और उस के साथ {}अपने रास्ते के बिना पाया पथ नाम की basename में शामिल होंगे (लेकिन जीएनयू findअभी भी साथ basename उपसर्ग जाएगा ./, जबकि बीएसडी findऐसा नहीं करेंगे)।
उदाहरण:
find . -type f -name '*.txt' \
-execdir mv {} done-texts/{}.done \;
यह प्रत्येक पाया *.txt-file को उसी निर्देशिका में पहले से मौजूद done-textsउपनिर्देशिका में ले जाएगा जहाँ फ़ाइल मिली थी । इसमें प्रत्यय जोड़कर फाइल का भी नाम बदल दिया जाएगा .done।
यह करने के लिए थोड़ा पेचीदा मामला -execहोगा क्योंकि हमें फ़ाइल {}का नया नाम बनाने के लिए मिली हुई फ़ाइल का बेसनेम प्राप्त करना होगा । हमें निर्देशिका का नाम ठीक से निर्देशिका {}का पता लगाने के लिए भी चाहिए done-texts।
इसके साथ -execdir, कुछ चीजें आसान हो जाती हैं।
इसके -execबजाय ऑपरेशन का उपयोग करके -execdirएक बच्चे के खोल को नियोजित करना होगा:
find . -type f -name '*.txt' -exec sh -c '
for name do
mv "$name" "$( dirname "$name" )/done-texts/$( basename "$name" ).done"
done' sh {} +
या,
find . -type f -name '*.txt' -exec sh -c '
for name do
mv "$name" "${name%/*}/done-texts/${name##*/}.done"
done' sh {} +