बैश शेल स्क्रिप्ट में `ls` परिणाम के माध्यम से पाशन


81

क्या किसी के पास कुछ करने के लिए टेम्प्लेट शेल स्क्रिप्ट है ls निर्देशिका नामों की सूची के लिए और प्रत्येक के माध्यम से पाशन करना और कुछ करना?

मैं करने की योजना बना रहा हूं ls -1d */ निर्देशिका नामों की सूची प्राप्त करने के लिए।

जवाबों:


86

@ शॉन-ज-गॉफ और अन्य लोगों द्वारा सुझाए गए अनुसार एलएस का उपयोग न करने का निर्णय लिया गया।

बस एक का उपयोग करें 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

19
क्या होगा अगर फ़ाइलनाम में एक जगह है?
Daniel A. White

4
दुर्भाग्य से, जैसा कि डैनियल ने कहा, इस उत्तर में कोड टूट जाएगा यदि फ़ाइलों या फ़ोल्डरों में से किसी के नाम में कोई स्थान या नई रेखा होती है। यह बहुत आम दुरुपयोग दर्शाता है for छोरों, और के उत्पादन को पार्स करने की कोशिश करने का एक विशिष्ट नुकसान ls। @ डैनियल.हाइट, यू पराक्रम इस उत्तर को अस्वीकार्य मानें यदि यह सहायक नहीं था (या संभावित रूप से भ्रामक है), जैसा कि आपने कहा, आप निर्देशिकाओं पर काम कर रहे हैं। शॉन जे। गोफ के जवाब को आपके मुद्दे का अधिक मजबूत और काम करने वाला समाधान प्रदान करना चाहिए।
slhck

4
-∞ आपको पार्स नहीं करना चाहिए ls उत्पादन , आपको आउटपुट नहीं पढ़ना चाहिए for पाश , आपको उपयोग करना चाहिए $() इसके बजाय `` और अधिक उद्धरण ™ का उपयोग करें । मुझे यकीन है कि @CoverosGene का मतलब अच्छी तरह से है, लेकिन यह सिर्फ भयानक है।
l0b0

1
एक बेहतर विकल्प यदि आप वास्तव में उपयोग करना चाहते हैं ls है ls -1 | while read line; do stuff; done। कम से कम वह व्हॉट्सएप के लिए नहीं टूटेगा।
Emmanuel Joubaud

1
साथ में mv -v आपको जरूरत नहीं है echo "moved $x -> $t"
DmitrySandalov

63

के आउटपुट का उपयोग करना 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 खुद के लिए उपभोग करने के बजाय; विशेष रूप से इसका इलाज न करने के लिए शेल प्राप्त करने का एक और तरीका यह है कि इसे उद्धरणों में रखें ';' साथ ही साथ काम करता है \; इस उद्देश्य के लिए।


2
+1 यह निश्चित रूप से जाने का तरीका है जब आपको एक फ़ाइल सूची बनाने और इसे एक कमांड में उपयोग करने की आवश्यकता होती है। ढूँढें -exec केवल एक कमांड चलाने में सक्षम होने से सीमित है। लूप के साथ, आप अपने दिल की सामग्री को पाइप कर सकते हैं।
MaQleod

+1। काश और लोग भी इसका इस्तेमाल करते find। जादू है जो किया जा सकता है, और यहां तक ​​कि कथित सीमाएं भी -exec चारों ओर काम किया जा सकता है। -print0 विकल्प भी उपयोग के लिए मूल्यवान है xargs
ghoti

8

रिक्त स्थान वाली फ़ाइलों के लिए आपको चर को उद्धृत करना सुनिश्चित करना होगा जैसे:

 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;

पहले उदाहरण में एक उपखंड का अच्छा उपयोग
Jeremy L

असाइनमेंट के बाद और नए चरित्र से पहले IFS को $ की आवश्यकता क्यों है?
Andy Ibanez

3
फिल्म के नाम में भी नई भूमिकाएं हो सकती हैं। पर टूट रहा है \n अपर्याप्त है। के उत्पादन को पार्स करने की सिफारिश करना कभी भी अच्छा विचार नहीं है ls
ghoti

5

यदि आपके पास जीएनयू समानांतर है 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


4

सिर्फ CoverosGene के जवाब में जोड़ने के लिए, यहाँ सिर्फ निर्देशिका नामों को सूचीबद्ध करने का एक तरीका है:

for f in */; do
  echo "Directory -> $f"
done

1

क्यों 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


2
फ़ाइलनाम में नई लाइनें भी हो सकती हैं, और वे अक्सर तब होती हैं जब उपयोगकर्ताओं को अपनी फ़ाइलों को नाम देने की अनुमति होती है। पर टूट रहा है \n अपर्याप्त है। एकमात्र मान्य समाधान पथनाम विस्तार के साथ लूप के लिए उपयोग करते हैं, या find
ghoti

फ़ाइल नामों की सूची को स्थानांतरित करने का एकमात्र विश्वसनीय तरीका उन्हें एनयूएल चरित्र के साथ अलग करना है, क्योंकि यह एकमात्र है जो निश्चित रूप से फ़ाइल पथ में निहित नहीं है।
glglgl

-3

यह है कि मैं इसे कैसे करता हूं, लेकिन संभवतः अधिक कुशल तरीके हैं।

ls > filelist.txt

while read filename; do echo filename: "$filename"; done < filelist.txt

6
फ़ाइल के स्थान पर पाइप से चिपके रहें: & gt; ls | while read i; do echo filename: $i; done
Jeremy L

ठंडा। मुझे कहना चाहिए कि आप दोनों कमांड के बीच में $ EDITOR filelist.txt का भी उपयोग कर सकते हैं। एक सामान जो आप एक संपादक में कर सकते हैं जो कमांड लाइन की तुलना में आसान है। इस सवाल के लिए प्रासंगिक नहीं है, हालांकि।
TREE

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