फाइंड कमांड से पाई जाने वाली फ़ाइल का नाम हेरफेर करें


10

मैं बैश करने के लिए अपेक्षाकृत नया हूं और कुछ ऐसा करने की कोशिश कर रहा हूं, जो सतह पर बहुत सीधा-सा लग रहा था - एक निर्देशिका पदानुक्रम पर सभी * .wma फ़ाइलों को प्राप्त करने के लिए रन करें, उस आउटपुट को एक कमांड पर पाइप करें जहां मैं उन्हें एमपी 3 में परिवर्तित करता हूं। रूपांतरित फ़ाइल को .mp3 पर सहेजें। मेरी सोच यह थी कि कमांड निम्नलिखित की तरह दिखना चाहिए (मैंने ऑडियो रूपांतरण कमांड को छोड़ दिया है और उदाहरण के लिए प्रतिध्वनि का उपयोग कर रहा हूं):

$ find ./ -name '*.wma' -type f -print0 | xargs -0 -I f echo ${f%.*}.mp3

जैसा कि मैं इसे समझता हूं, -print0 arg मुझे उन फ़ाइलनामों को संभालने देगा जिनके पास रिक्त स्थान हैं (जो इनमें से कई करते हैं क्योंकि वे संगीत हैं)। मैं तब (xargs के परिणामस्वरूप) उम्मीद कर रहा हूं कि खोजने से प्रत्येक फ़ाइल पथ f में कैप्चर किया गया है, और स्ट्रिंग के अंत से सबस्ट्रिंग मैच / डिलीट का उपयोग करते हुए, कि मुझे मूल फ़ाइल पथ को एक एमपी 3 के साथ गूंजना चाहिए अर्थोपाय अग्रिम के बजाय। हालाँकि, इस परिणाम के बजाय, मैं निम्नलिखित देख रहा हूँ:

*.mp3
*.mp3
*.mp3
*.mp3
*.mp3
*.mp3
*.mp3
*.mp3
*.mp3
...

तो मेरा सवाल (विशिष्ट से अलग 'मैं यहाँ क्या गलत कर रहा हूँ'), यह है - वे मान जो एक पाइप ऑपरेशन के परिणाम हैं, उन्हें स्ट्रिंग हेरफेर संचालन में अलग-अलग व्यवहार करने की आवश्यकता होती है, जो कि एक चर असाइनमेंट का परिणाम है। ?


1
के xargsसाथ उपयोग करने का कोई कारण नहीं है find। यह एक -execविकल्प के साथ आता है । क्या आप अपने आदेश का उपयोग केवल अपने प्रश्न में करने के लिए कर सकते हैं, और कोई आपको सही findआदेश दिखा सकता है ?
ixtmixilix

हाँ (जैसा कि मैंने नीचे उल्लेख किया है), इसलिए जब तक मैं अभी भी खोज आदेश के प्रत्येक परिणाम पर स्ट्रिंग हेरफेर कर सकता हूं (उदाहरण के लिए {}सदस्य)
हावर्ड डिएरकिंग

वास्तव में ऐसे किनारे मामले हैं जहां xargsकी तुलना में अधिक उपयुक्त है exec। इस stackpost देखें stackoverflow.com/questions/896808/find-exec-cmd-vs-xargs बिंदु में एक मामले के लिए।
d34dh0r53

@ d34dh0r53 क्या है किनारा मामला? आपके द्वारा लिंक किया गया थ्रेड किसी भी बिंदु को इंगित नहीं करता है।
गिल्स एसओ- बुराई को रोकना '

जवाबों:


8

जैसा कि अन्य उत्तरों ने पहले ही पहचान लिया है, कमांड ${f%.*}चलाने से पहले शेल द्वारा विस्तारित किया जाता है xargs। आपको प्रत्येक फ़ाइल नाम के लिए एक बार होने के लिए इस विस्तार की आवश्यकता है, शेल चर के साथ फ़ाइल नाम पर fसेट करें (पासिंग -I fऐसा नहीं करता है: xargsशेल चर की कोई धारणा नहीं है, यह fकमांड में स्ट्रिंग की तलाश करता है, इसलिए यदि आप चाहते हैं प्रयोग किया जाता है जैसे xargs -I e echo …कि यह कमांड को निष्पादित करेगा ./somedir/somefile.wmacho .mp3)।

इस दृष्टिकोण को ध्यान में रखते हुए, xargsएक शेल को लागू करने के लिए कहें जो विस्तार कर सकता है। बेहतर, बताओ find- xargsएक काफी हद तक अप्रचलित उपकरण है और सही तरीके से उपयोग करना कठिन है, क्योंकि आधुनिक संस्करणों के निर्माण में कम प्लंबिंग कठिनाइयों के साथ एक ही काम (और अधिक) करता है। इसके बजाय find … -print0 | xargs -0 command …, भागो find … -exec command … {} +

find . -name '*.wma' -type f -exec sh -c 'for f; do echo "${f%.*}.mp3"; done' _ {} +

तर्क _है $0खोल में; फ़ाइल नाम स्थितीय तर्कों के रूप में पारित किए जाते हैं जो for f; do …खत्म हो जाते हैं। इस आदेश का एक सरल संस्करण प्रत्येक फ़ाइल के लिए एक अलग शेल निष्पादित करता है, जो समतुल्य लेकिन थोड़ा धीमा है:

find . -name '*.wma' -type f -exec sh -c 'echo "${0%.*}.mp3"' {} \;

आपको वास्तव में findयहां उपयोग करने की आवश्यकता नहीं है, यह मानते हुए कि आप हालिया शेल खोल रहे हैं (ksh93, bash ≥4.0, या za)। बाश में, shopt -s globstarअपने .bashrcको **/उपनिर्देशिकाओं (ksh, कि set -o globstar) में पुनरावृत्ति करने के लिए ग्लोब पैटर्न को सक्रिय करने के लिए डाल दिया । तब तुम दौड़ सकते हो

for f in **/*.wma; do
  echo "${f%.*}.mp3"
done

(यदि आपके पास निर्देशिकाएं हैं *.wma, [ -f "$f" ] || continueतो लूप की शुरुआत में जोड़ें ।)


महान व्याख्याओं के साथ-साथ मुझे एक ऐसी दिशा में इंगित किया, जिसे मैंने महसूस भी नहीं किया था (ग्लोबस्टार कार्यक्षमता प्राप्त करने के लिए अपने बैश शेल को अपग्रेड करना) - अंत में, पुनरावर्ती ग्लोबिंग वह समाधान था जो कमांड को सरल रखता था और जो कुछ मैं करने की कोशिश कर रहा था उसे पूरा किया। । धन्यवाद!
हावर्ड डिएरकिंग

6

आपके समाधान के मामले में $ {f%। *}। Mp3 का मूल्यांकन शेल में किया जाता है, जिसे आप पूरे कमांड में शामिल कर रहे हैं, न कि xargs द्वारा फोर्क किए गए शेल में । और तुम्हारे खोल में कोई नहीं है वेरिएबल है, इसे एक खाली स्ट्रिंग द्वारा प्रतिस्थापित किया जाता है।

-I f के साथ xargs का उपयोग कर समाधान :

% cat 1.sh 
#!/bin/sh
f=$1
echo ${f%.*}.mp3
% /bin/ls -1
1.sh
aaa.wma
bbbb.wma
ccccc.wma
% find ./ -name '*.wma' -type f -print0 | xargs -0 -I f ./1.sh f
./aaa.mp3
./ccccc.mp3
./bbbb.mp3

लेकिन मैं इसे इस तरह से करूंगा:

% find ./ -name '*.wma' -type f | sed 's,\.wma$,.mp3,'
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.