lsডিরেক্টরি নামের তালিকার জন্য প্রত্যেকটির মধ্যে লুপিং এবং কিছু করার জন্য কারও কাছে কি টেম্পলেট শেল স্ক্রিপ্ট রয়েছে ?
আমি ls -1d */ডিরেক্টরি নামের তালিকা পেতে করতে পরিকল্পনা করছি ।
lsডিরেক্টরি নামের তালিকার জন্য প্রত্যেকটির মধ্যে লুপিং এবং কিছু করার জন্য কারও কাছে কি টেম্পলেট শেল স্ক্রিপ্ট রয়েছে ?
আমি ls -1d */ডিরেক্টরি নামের তালিকা পেতে করতে পরিকল্পনা করছি ।
উত্তর:
@ শান-জে-গফ এবং অন্যরা পরামর্শ হিসাবে যেমন কোনও গ্লোব করবে সেখানে এলএস ব্যবহার না করার জন্য সম্পাদিত।
কেবল একটি for..do..doneলুপ ব্যবহার করুন :
for f in *; do
echo "File -> $f"
done
আপনি প্রতিস্থাপন করতে পারেন *সঙ্গে *.txtবা অন্য কোন উল্লিখিত glob করে একটি তালিকা (ফাইল, ডিরেক্টরি, বা কিছু যে বিষয়টি জন্য) ফেরৎ, একটি কমান্ড করে একটি তালিকা তৈরি করে, যেমন, $(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। @ DanielA.White, আপনি পারে যদি এটি সহায়ক ছিল না (বা সম্ভাব্য বিভ্রান্তিকর) এই উত্তর unaccepting বিবেচনা, যেহেতু হচ্ছে আপনি বলেন, আপনি ডিরেক্টরি অভিনয় করছি। শন জে গফের জবাবটি আপনার ইস্যুতে আরও দৃ rob় এবং কার্যকর সমাধান প্রদান করবে।
lsআউটপুট , আপনি একটি আউটপুট পড়া উচিত নয় forলুপ , আপনি ব্যবহার করা উচিত $()`পরিবর্তে এবং আরো কোট ব্যবহার ™ । আমি নিশ্চিত @ কভারোসজিনের অর্থ ভাল, তবে এটি কেবল ভয়াবহ।
lsহয় ls -1 | while read line; do stuff; done। কমপক্ষে যেটি সাদা জায়গার জন্য ভাঙবে না।
mv -vদরকার নেইecho "moved $x -> $t"
lsফাইলের নাম পেতে আউটপুট ব্যবহার করা একটি খারাপ ধারণা । এটি ত্রুটিযুক্ত এমনকি বিপজ্জনক স্ক্রিপ্টগুলিতে বাড়ে। এর কারণ একটি ফাইল ছাড়া কোনো চরিত্র ধারণ করতে পারে /এবং nullঅক্ষর, এবং lsবিভেদক হিসাবে যারা অক্ষরের পারেন ব্যবহার করে না, তাই একটি ফাইলের নাম একটি স্থান বা একটি newline হয়ে থাকে, আপনি হবে অপ্রত্যাশিত ফলাফল পেতে।
ফাইলগুলির মাধ্যমে পুনরাবৃত্তি করার দুটি খুব ভাল উপায় রয়েছে। এখানে, আমি echoফাইলের নাম দিয়ে কিছু করার জন্য সহজভাবে ব্যবহার করেছি ; আপনি কিছু ব্যবহার করতে পারেন, যদিও।
প্রথমটি হ'ল শেলের দেশীয় গ্লোববিং বৈশিষ্ট্যগুলি ব্যবহার করা।
for dir in */; do
echo "$dir"
done
শেলটি */পৃথক যুক্তিগুলিতে বিস্তৃত হয় যা forলুপটি পড়ে; এমনকি ফাইলের forনামের মধ্যে কোনও স্থান, নিউলাইন বা অন্য কোনও অদ্ভুত চরিত্র থাকলেও প্রতিটি সম্পূর্ণ নামটিকে পরমাণু ইউনিট হিসাবে দেখবে; এটি কোনওভাবেই তালিকাকে পার্সিং করছে না।
আপনি সাবডিরেক্টরি মধ্যে যাও recursively যেতে চান, তাহলে এই যদি না আপনার শেল যেমন (কিছু বাড়ানো globbing বৈশিষ্ট্য আছে কি করতে হবে না bash'এর globstar। আপনার শেল এই বৈশিষ্ট্যগুলি না থাকে, বা যে আপনার স্ক্রিপ্টের কাজ করবে যদি তোমরা নিশ্চিত করতে চাই বিভিন্ন সিস্টেমে, তারপরে পরবর্তী বিকল্পটি ব্যবহার করা হবে find।
find . -type d -exec echo '{}' \;
এখানে, findকমান্ড কল করে echoএটিকে ফাইল নামের একটি যুক্তি দিয়ে দেবে। এটি খুঁজে পাওয়া প্রতিটি ফাইলের জন্য এটি এটি করে। পূর্ববর্তী উদাহরণের মতো, ফাইলের নামের তালিকার কোনও বিশ্লেষণ নেই; পরিবর্তে, একটি ফাইলনেম সম্পূর্ণরূপে একটি আর্গুমেন্ট হিসাবে প্রেরণ করা হয়।
তর্কটির বাক্য গঠনটি -execএকটু মজার দেখাচ্ছে looks findএর পরে প্রথম যুক্তিটি গ্রহণ করে -execএবং প্রোগ্রামটি চালানো হিসাবে আচরণ করে এবং পরবর্তী প্রতিটি আর্গুমেন্ট, সেই প্রোগ্রামে যাওয়ার জন্য একটি আর্গুমেন্ট হিসাবে গ্রহণ করে। দুটি বিশেষ যুক্তি যা -execদেখার দরকার। প্রথমটি হ'ল {}; এই যুক্তিটি ফাইলের নামের সাথে প্রতিস্থাপিত হয় যা পূর্ববর্তী অংশগুলি findউত্পন্ন করে। দ্বিতীয়টি হ'ল এটি ;যা findপ্রোগ্রামটিতে পাস করার জন্য আর্গুমেন্টের তালিকার শেষ এটি জানতে দেয় ; এটির findদরকার কারণ আপনি আরও বেশি যুক্তি দিয়ে চালিয়ে যেতে পারেন findযা কার্যকর করা প্রোগ্রামটির উদ্দেশ্যে নয় এবং নয়। এর কারণটি \হ'ল শেলটিও আচরণ করে;বিশেষত - এটি একটি কমান্ডের শেষের প্রতিনিধিত্ব করে, সুতরাং আমাদের এটিকে এড়িয়ে চলতে হবে যাতে শেল findএটি নিজের জন্য ব্যয় না করে যুক্তি হিসাবে দেয় ; শেলটি বিশেষভাবে চিকিত্সা না করানোর আরেকটি উপায় হ'ল এটিকে উদ্ধৃতিতে রাখা: ';'ঠিক একই \;উদ্দেশ্যে কাজ করে।
find। এমন যাদু রয়েছে যা করা যায় এবং এর সীমাবদ্ধতাগুলিও -execপ্রায় কাজ করা যায়। -print0বিকল্পটি সাথে ব্যবহারের জন্য মূল্যবান xargs।
স্পেস সহ ফাইলগুলির জন্য আপনাকে অবশ্যই ভেরিয়েবলের উদ্ধৃতি দিতে হবে:
for i in $(ls); do echo "$i"; done;
বা, আপনি ইনপুট ফিল্ড বিভাজক (আইএফএস) পরিবেশ পরিবর্তনশীল পরিবর্তন করতে পারেন:
IFS=$'\n';for file in $(ls); do echo $i; done
অবশেষে, আপনি যা করছেন তার উপর নির্ভর করে আপনার এমনকি এলএসের প্রয়োজনও পড়বে না:
for i in *; do echo "$i"; done;
\nঅপর্যাপ্ত। এর আউটপুট বিশ্লেষণ করার পরামর্শ দেওয়া কখনই ভাল ধারণা নয় ls।
আপনার যদি জিএনইউ সমান্তরাল http://www.gnu.org/software/parallel/ ইনস্টল থাকে তবে আপনি এটি করতে পারেন:
ls | parallel echo {} is in this dir
.XML থেকে সমস্ত .txt- এর নতুন নামকরণ করতে:
ls *.txt | parallel mv {} {.}.xml
আরও জানতে জিএনইউ সমান্তরালের জন্য অন্তর্ভুক্ত ভিডিওটি দেখুন: http://www.youtube.com/watch?v=OpaiGYxkSuQ
কেন একটি নতুন লাইনে আইএফএস সেট করে না, তারপরে lsএকটি অ্যারের আউটপুট ক্যাপচার করবেন ? আইএফএসকে নতুন লাইনে সেট করা ফাইল ফাইলের মজার চরিত্রের সাথে সমস্যাগুলি সমাধান করা উচিত; ব্যবহার করা দুর্দান্ত lsহতে পারে কারণ এতে একটি অন্তর্নির্মিত সাজানোর সুবিধা রয়েছে।
(পরীক্ষার সময় আমি আইএফএস স্থাপন করতে \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
এটি ওএস এক্সের ক্ষেত্রে বিশেষত কার্যকর, যেমন, তৈরির তারিখ অনুসারে বাছাই করা ফাইলগুলির তালিকা ক্রেডিট করতে (সবচেয়ে পুরানো থেকে নতুন) 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