ash ls` এর মধ্য দিয়ে লুপিং বাশ শেল স্ক্রিপ্টের ফলাফল


93

lsডিরেক্টরি নামের তালিকার জন্য প্রত্যেকটির মধ্যে লুপিং এবং কিছু করার জন্য কারও কাছে কি টেম্পলেট শেল স্ক্রিপ্ট রয়েছে ?

আমি ls -1d */ডিরেক্টরি নামের তালিকা পেতে করতে পরিকল্পনা করছি ।

উত্তর:


109

@ শান-জে-গফ এবং অন্যরা পরামর্শ হিসাবে যেমন কোনও গ্লোব করবে সেখানে এলএস ব্যবহার না করার জন্য সম্পাদিত।

কেবল একটি 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

22
যদি ফাইলনামের মধ্যে একটি জায়গা থাকে?
ড্যানিয়েল এ। হোয়াইট

4
দুর্ভাগ্যক্রমে, যেমন ড্যানিয়েল বলেছেন, এই উত্তরের কোডটি ভেঙে যাবে যদি কোনও ফাইল বা ফোল্ডারে তাদের নামে একটি স্পেস বা নিউলাইন থাকে। এটি forলুপগুলির একটি খুব সাধারণ অপব্যবহার এবং এর আউটপুটকে বিশ্লেষণ করার চেষ্টা করার একটি সাধারণ ক্ষতি দেখায় ls। @ DanielA.White, আপনি পারে যদি এটি সহায়ক ছিল না (বা সম্ভাব্য বিভ্রান্তিকর) এই উত্তর unaccepting বিবেচনা, যেহেতু হচ্ছে আপনি বলেন, আপনি ডিরেক্টরি অভিনয় করছি। শন জে গফের জবাবটি আপনার ইস্যুতে আরও দৃ rob় এবং কার্যকর সমাধান প্রদান করবে।
23:43

4
-∞ আপনি পার্স করা উচিত নয় lsআউটপুট , আপনি একটি আউটপুট পড়া উচিত নয় forলুপ , আপনি ব্যবহার করা উচিত $()`পরিবর্তে এবং আরো কোট ব্যবহার ™ । আমি নিশ্চিত @ কভারোসজিনের অর্থ ভাল, তবে এটি কেবল ভয়াবহ।
l0b0

1
একটি ভালো বিকল্প যদি সত্যিই ব্যবহার করতে চান lsহয় ls -1 | while read line; do stuff; done। কমপক্ষে যেটি সাদা জায়গার জন্য ভাঙবে না।
ইমানুয়েল জৌবাউদ

1
সঙ্গে mv -vদরকার নেইecho "moved $x -> $t"
DmitrySandalov

68

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এটি নিজের জন্য ব্যয় না করে যুক্তি হিসাবে দেয় ; শেলটি বিশেষভাবে চিকিত্সা না করানোর আরেকটি উপায় হ'ল এটিকে উদ্ধৃতিতে রাখা: ';'ঠিক একই \;উদ্দেশ্যে কাজ করে।


2
আপনার ফাইল ফাইল তৈরি করতে এবং কমান্ডে এটি ব্যবহার করার দরকার পরে অবশ্যই এটি যাওয়ার উপায়। সন্ধান-এক্সেক কেবলমাত্র একটি কমান্ড চালাতে সক্ষম হয়ে সীমাবদ্ধ। লুপের সাহায্যে, আপনি আপনার হৃদয়ের সামগ্রীতে পাইপ করতে পারেন।
ম্যাক্লিওড

+1 টি। আমি আশা করি আরও লোক ব্যবহার করতে পারে find। এমন যাদু রয়েছে যা করা যায় এবং এর সীমাবদ্ধতাগুলিও -execপ্রায় কাজ করা যায়। -print0বিকল্পটি সাথে ব্যবহারের জন্য মূল্যবান xargs
ঘোটি

লুপ বিকল্পটি লুকানো ডিরেক্টরিগুলি দেখায় না। সন্ধানের বিকল্পটি প্রতীক দেখায় না ´
জিনউই

15

স্পেস সহ ফাইলগুলির জন্য আপনাকে অবশ্যই ভেরিয়েবলের উদ্ধৃতি দিতে হবে:

 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;

প্রথম উদাহরণে সাবসেলের দুর্দান্ত ব্যবহার
জেরেমি এল

নিয়োগের পরে এবং নতুন চরিত্রের আগে আইএফএসের কেন একটি need প্রয়োজন?
অ্যান্ডি ইবনেজ

3
ফাইলের নামগুলিতেও নতুন লাইন থাকতে পারে। ব্রেকিং \nঅপর্যাপ্ত। এর আউটপুট বিশ্লেষণ করার পরামর্শ দেওয়া কখনই ভাল ধারণা নয় ls
ঘোটি

5

আপনার যদি জিএনইউ সমান্তরাল 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


4

কভারোসগিনের উত্তরে কেবল যুক্ত করতে এখানে কেবলমাত্র ডিরেক্টরির নাম তালিকাভুক্ত করার একটি উপায়:

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

1

কেন একটি নতুন লাইনে আইএফএস সেট করে না, তারপরে 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


2
ফাইলের নামগুলিতে নিউলাইনগুলিও থাকতে পারে এবং ব্যবহারকারীরা যখন তাদের নিজস্ব ফাইলের নাম দেওয়ার অনুমতি পান তখন তারা তা করে। ব্রেকিং \nঅপর্যাপ্ত। একমাত্র বৈধ সমাধানগুলি পথের নাম সম্প্রসারণ সহ লুপের জন্য ব্যবহার করে বা find
ঘোটি

ফাইলের নামের তালিকা হস্তান্তর করার একমাত্র নির্ভরযোগ্য উপায় হ'ল এগুলি NUL অক্ষর দ্বারা পৃথক করা, কারণ এটিই কেবলমাত্র কোনও ফাইল পাথের অন্তর্ভুক্ত নয়।
glglgl

-3

এইভাবেই আমি এটি করি তবে সম্ভবত আরও কার্যকর উপায় রয়েছে।

ls > filelist.txt

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

6
ফাইলের জায়গায় পাইপের সাথে ls | while read i; do echo filename: $i; done
জেরেমি এল

কুল। আমার বলা উচিত যে আপনি দুটি কমান্ডের মধ্যে $ EDITOR filelist.txt ব্যবহার করতে পারেন। কমান্ড লাইনের চেয়ে সহজ কোনও সম্পাদকের মধ্যে আপনি অনেক কিছুই করতে পারেন। যদিও এই প্রশ্নের সাথে প্রাসঙ্গিক নয়।
তিনি TREE

আপনার সমাধানটি নতুন লাইনের এবং অন্যান্য অভিনব স্টাফযুক্ত ফাইলের নামগুলির সাথে সমস্যার সমাধান করে না।
glglgl
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.