क्या किसी के पास कुछ करने के लिए टेम्प्लेट शेल स्क्रिप्ट है ls
निर्देशिका नामों की सूची के लिए और प्रत्येक के माध्यम से पाशन करना और कुछ करना?
मैं करने की योजना बना रहा हूं ls -1d */
निर्देशिका नामों की सूची प्राप्त करने के लिए।
क्या किसी के पास कुछ करने के लिए टेम्प्लेट शेल स्क्रिप्ट है ls
निर्देशिका नामों की सूची के लिए और प्रत्येक के माध्यम से पाशन करना और कुछ करना?
मैं करने की योजना बना रहा हूं ls -1d */
निर्देशिका नामों की सूची प्राप्त करने के लिए।
जवाबों:
@ शॉन-ज-गॉफ और अन्य लोगों द्वारा सुझाए गए अनुसार एलएस का उपयोग न करने का निर्णय लिया गया।
बस एक का उपयोग करें for..do..done
पाश:
for f in *; do
echo "File -> $f"
done
आप प्रतिस्थापित कर सकते हैं *
साथ में *.txt
या कोई अन्य ग्लोब जो किसी सूची (फ़ाइलों, निर्देशिकाओं या उस मामले के लिए कुछ भी) को लौटाता है, एक कमांड जो एक सूची बनाता है, उदा।, $(cat filelist.txt)
, या वास्तव में इसे एक सूची के साथ बदलें।
के अंदर do
लूप, आप बस डॉलर के उपसर्ग के साथ लूप वेरिएबल को देखें $f
उपरोक्त उदाहरण में)। आप ऐसा कर सकते हैं echo
यह या आप चाहते हैं कि यह करने के लिए कुछ और करते हैं।
उदाहरण के लिए, सभी का नाम बदलने के लिए .xml
वर्तमान निर्देशिका में फ़ाइलें .txt
:
for x in *.xml; do
t=$(echo $x | sed 's/\.xml$/.txt/');
mv $x $t && echo "moved $x -> $t"
done
या इससे भी बेहतर, यदि आप बैश का उपयोग कर रहे हैं, तो आप एक सबशेलिंग को स्पॉन करने के बजाय बैश पैरामीटर विस्तार का उपयोग कर सकते हैं:
for x in *.xml; do
t=${x%.xml}.txt
mv $x $t && echo "moved $x -> $t"
done
for
छोरों, और के उत्पादन को पार्स करने की कोशिश करने का एक विशिष्ट नुकसान ls
। @ डैनियल.हाइट, यू पराक्रम इस उत्तर को अस्वीकार्य मानें यदि यह सहायक नहीं था (या संभावित रूप से भ्रामक है), जैसा कि आपने कहा, आप निर्देशिकाओं पर काम कर रहे हैं। शॉन जे। गोफ के जवाब को आपके मुद्दे का अधिक मजबूत और काम करने वाला समाधान प्रदान करना चाहिए।
ls
उत्पादन , आपको आउटपुट नहीं पढ़ना चाहिए for
पाश , आपको उपयोग करना चाहिए $()
इसके बजाय `` और अधिक उद्धरण ™ का उपयोग करें । मुझे यकीन है कि @CoverosGene का मतलब अच्छी तरह से है, लेकिन यह सिर्फ भयानक है।
ls
है ls -1 | while read line; do stuff; done
। कम से कम वह व्हॉट्सएप के लिए नहीं टूटेगा।
mv -v
आपको जरूरत नहीं है echo "moved $x -> $t"
के आउटपुट का उपयोग करना ls
फ़ाइल नाम प्राप्त करना एक बुरा विचार है । यह खराबी और खतरनाक लिपियों को जन्म दे सकता है। ऐसा इसलिए है क्योंकि फ़ाइल नाम में किसी भी वर्ण को छोड़कर कोई भी हो सकता है /
और यह null
चरित्र, और ls
उन पात्रों में से किसी को भी सीमांकक के रूप में उपयोग नहीं किया जाता है, इसलिए यदि फ़ाइल नाम में स्थान या नई रेखा है, तो आप मर्जी अप्रत्याशित परिणाम प्राप्त करें।
फ़ाइलों पर पुनरावृत्ति के दो बहुत अच्छे तरीके हैं। यहाँ, मैंने बस इस्तेमाल किया है echo
फ़ाइल नाम के साथ कुछ करने का प्रदर्शन करने के लिए; आप कुछ भी उपयोग कर सकते हैं, हालांकि।
पहली बार शेल की मूल ग्लोबिंग विशेषताओं का उपयोग करना है।
for dir in */; do
echo "$dir"
done
खोल फैलता है */
अलग-अलग तर्कों में कि ए for
लूप पढ़ता है; भले ही फ़ाइल नाम में कोई स्थान, नई रेखा, या कोई अन्य अजीब चरित्र हो, for
एक परमाणु इकाई के रूप में प्रत्येक पूरा नाम देखेंगे; यह किसी भी तरह से सूची को पार्स नहीं कर रहा है।
यदि आप उप-सीमाओं में पुनरावर्ती रूप से जाना चाहते हैं, तो यह तब तक नहीं होगा जब तक आपके शेल में कुछ विस्तारित ग्लोबिंग सुविधाएँ नहीं होंगी (जैसे कि bash
की globstar
। यदि आपके शेल में ये विशेषताएं नहीं हैं, या यदि आप यह सुनिश्चित करना चाहते हैं कि आपकी स्क्रिप्ट विभिन्न प्रणालियों पर काम करेगी, तो अगला विकल्प उपयोग करना है find
।
find . -type d -exec echo '{}' \;
यहां ही find
कमांड बुलाएगा echo
और इसे फ़ाइल नाम का एक तर्क दें। यह प्रत्येक फ़ाइल के लिए एक बार ऐसा करता है। पिछले उदाहरण के साथ, फ़ाइल नाम की सूची का कोई पार्सिंग नहीं है; इसके बजाय, एक फिलामेंट को पूरी तरह से एक तर्क के रूप में भेजा जाता है।
का वाक्य विन्यास -exec
तर्क थोड़ा मजाकिया लगता है। find
के बाद पहला तर्क लेता है -exec
और व्यवहार करता है कि कार्यक्रम को चलाने के लिए, और प्रत्येक बाद के तर्क के रूप में, उस कार्यक्रम को पारित करने के लिए एक तर्क के रूप में लेता है। दो विशेष तर्क हैं -exec
देखने की जरूरत है। पहले वाला है {}
; इस तर्क को उस फ़ाइलनाम से बदल दिया जाता है जिसके पिछले भाग हैं find
उत्पन्न करता है। दूसरा वाला है ;
, जो देता है find
पता है कि यह कार्यक्रम को पारित करने के लिए तर्कों की सूची का अंत है; find
इसकी आवश्यकता है क्योंकि आप और अधिक तर्कों के साथ जारी रख सकते हैं, जिनके लिए इरादा है find
और निष्पादन कार्यक्रम के लिए अभिप्रेत नहीं है। का कारण \
यह है कि खोल भी व्यवहार करता है ;
विशेष रूप से - यह एक कमांड के अंत का प्रतिनिधित्व करता है, इसलिए हमें इसे बचने की ज़रूरत है ताकि शेल इसे तर्क के रूप में दे find
खुद के लिए उपभोग करने के बजाय; विशेष रूप से इसका इलाज न करने के लिए शेल प्राप्त करने का एक और तरीका यह है कि इसे उद्धरणों में रखें ';'
साथ ही साथ काम करता है \;
इस उद्देश्य के लिए।
find
। जादू है जो किया जा सकता है, और यहां तक कि कथित सीमाएं भी -exec
चारों ओर काम किया जा सकता है। -print0
विकल्प भी उपयोग के लिए मूल्यवान है xargs
।
रिक्त स्थान वाली फ़ाइलों के लिए आपको चर को उद्धृत करना सुनिश्चित करना होगा जैसे:
for i in $(ls); do echo "$i"; done;
या, आप इनपुट फ़ील्ड सेपरेटर (IFS) परिवेश चर को बदल सकते हैं:
IFS=$'\n';for file in $(ls); do echo $i; done
अंत में, आप क्या कर रहे हैं, इसके आधार पर, आपको ls की आवश्यकता भी नहीं हो सकती है:
for i in *; do echo "$i"; done;
\n
अपर्याप्त है। के उत्पादन को पार्स करने की सिफारिश करना कभी भी अच्छा विचार नहीं है ls
।
यदि आपके पास जीएनयू समानांतर है http://www.gnu.org/software/parallel/ स्थापित आप यह कर सकते हैं:
ls | parallel echo {} is in this dir
सभी .txt का .xml नाम बदलने के लिए:
ls *.txt | parallel mv {} {.}.xml
अधिक जानने के लिए GNU समानांतर के इंट्रो वीडियो देखें: http://www.youtube.com/watch?v=OpaiGYxkSuQ
क्यों IFS को एक नई सीमा पर सेट नहीं किया जाता है, तो इसके आउटपुट को कैप्चर करें ls
एक सरणी में? आईएफएस को नईलाइन पर सेट करना फ़ाइल नामों में मजेदार पात्रों के साथ मुद्दों को हल करना चाहिए; का उपयोग करते हुए ls
अच्छा हो सकता है क्योंकि इसमें एक अंतर्निहित सॉर्ट सुविधा है।
(परीक्षण में मुझे IFS को सेट करने में समस्या हो रही थी \n
लेकिन इसे नए क्षेत्र में स्थापित करने का काम करता है, जैसा कि यहाँ कहीं और सुझाया गया है):
जैसे (चाहा हुआ ls
में खोज पैटर्न पारित किया $1
):
SAVEIFS=$IFS
IFS=$(echo -en "\n\b")
FILES=($(/bin/ls "$1"))
for AFILE in ${FILES[@]}
do
... do something with a file ...
done
IFS=$SAVEIFS
यह OS X पर विशेष रूप से काम करता है, उदा। निर्माण तिथि (सबसे पुरानी से नवीनतम), द्वारा बनाई गई फ़ाइलों की सूची पर कब्जा करने के लिए ls
आज्ञा है ls -t -U -r
।
\n
अपर्याप्त है। एकमात्र मान्य समाधान पथनाम विस्तार के साथ लूप के लिए उपयोग करते हैं, या find
।
यह है कि मैं इसे कैसे करता हूं, लेकिन संभवतः अधिक कुशल तरीके हैं।
ls > filelist.txt
while read filename; do echo filename: "$filename"; done < filelist.txt
ls | while read i; do echo filename: $i; done