বাশ ব্যবহার করে প্রতিটি উপ-ডিরেক্টরিতে একটি ক্রিয়া সম্পাদন করুন


194

আমি এমন একটি স্ক্রিপ্টে কাজ করছি যা নির্দিষ্ট ফোল্ডারের প্রতিটি উপ-ডিরেক্টরিতে একটি ক্রিয়া করা প্রয়োজন।

এটি লেখার সবচেয়ে দক্ষ উপায় কী?


1
দয়া করে ফিরে আসার এবং সঠিকতার জন্য উত্তরগুলি পুনরায় মূল্যায়ন করার বিষয়টি বিবেচনা করুন - বড় বাগগুলি থাকা সত্ত্বেও আপনি একটি স্বীকৃত উত্তর পেয়েছেন (f / e, এটি এমন কোনও ডিরেক্টরিতে চালিত mkdir 'foo * bar'হবে যেখানে কেউ আগে দৌড়েছিল fooএবং কারণটি barপুনরুক্ত করা হবে) এগুলির অস্তিত্ব নেই, এবং সমস্ত ফাইলের নামের *সাথে , এমনকি ডিরেক্টরি নন-ডিরেক্টরিতেও প্রতিস্থাপন করা হবে )।
চার্লস ডফি

1
... এমনকি খারাপটি যদি কেউ দৌড়ে যায় mkdir -p '/tmp/ /etc/passwd /'- কেউ যদি এই অনুশীলনের পরে কোনও স্ক্রিপ্ট চালায় তবে /tmpবলুন, মুছতে ডিরেক্টরিগুলি সন্ধান করুন, তারা মুছে ফেলতে পারে /etc/passwd
চার্লস ডাফি

উত্তর:


177
for D in `find . -type d`
do
    //Do whatever you need with D
done

81
এটি সাদা স্থানগুলিতে ভেঙে যাবে
ghostdog74

2
এছাড়াও, মনে রাখবেন findযে আপনি পুনরাবৃত্তি বা অ-পুনরাবৃত্ত আচরণ করতে চাইলে আপনাকে প্যারামগুলি টুইট করতে হবে।
ক্রিস টোনকিনসন

32
উপরের উত্তরটি আমাকে স্ব-ডিরেক্টরিও দিয়েছে, সুতরাং নিম্নলিখিতগুলি আমার জন্য আরও কিছুটা ভাল কাজ করেছে: find . -mindepth 1 -type d
jzheaux

1
@ জোসসি, উভয় রূপই mkdir 'directory name with spaces'চারটি পৃথক শব্দের দ্বারা নির্মিত ডিরেক্টরিটি ভেঙে দেবে ।
চার্লস ডাফি

4
আমার যোগ করার দরকার ছিল -mindepth 1 -maxdepth 1বা এটি খুব গভীর হয়ে গেছে।
স্ক্র্যাপিদেভ

283

এমন একটি সংস্করণ যা উপ-প্রক্রিয়া তৈরি করা এড়িয়ে চলে:

for D in *; do
    if [ -d "${D}" ]; then
        echo "${D}"   # your processing here
    fi
done

অথবা, যদি আপনার ক্রিয়াটি একটি একক আদেশ হয় তবে এটি আরও সংক্ষিপ্ত:

for D in *; do [ -d "${D}" ] && my_command; done

বা আরও সংক্ষিপ্ত সংস্করণ ( ধন্যবাদ @ এঞ্জোটিব )। মনে রাখবেন যে এই সংস্করণে প্রতিটি মানের Dএকটি পিছনে স্ল্যাশ থাকবে:

for D in */; do my_command; done

48
আপনি ifবা এর [সাথে এড়াতে পারবেন :for D in */; do
এনজোটিব

2
+1 কারণ ডিরেক্টরি নামগুলি /। দিয়ে শুরু হয় না / গৃহীত উত্তরের বিপরীতে
হ্যারি উওর কলটুক

3
ডিরেক্টরিটি +1
অ্যালেক্স রিঙ্কিং

5
সর্বশেষ কমান্ডের সাথে একটি সমস্যা রয়েছে: আপনি যদি উপ-ডিরেক্টরি ছাড়া কোনও ডিরেক্টরিতে থাকেন; এটি "* /" ফিরে আসবে। সুতরাং দ্বিতীয় কমান্ড for D in *; do [ -d "${D}" ] && my_command; doneবা দুটি সর্বশেষের for D in */; do [ -d $D ] && my_command; done
দুটিয়ের

5
মনে রাখবেন যে এই উত্তরটি লুকানো ডিরেক্টরিগুলি উপেক্ষা করে। for D in .* *; doপরিবর্তে লুকানো ডিরেক্টরি অন্তর্ভুক্ত করতে ব্যবহার করুন for D in *; do
patryk.beza

105

সহজ পুনরাবৃত্তিযোগ্য উপায় হ'ল:

for d in */; do
    echo "$d"
done

দ্য /শেষে বলে, শুধুমাত্র ব্যবহার ডিরেক্টরি।

দরকার নেই

  • অনুসন্ধান
  • awk
  • ...

11
দ্রষ্টব্য: এতে ডট ডায়ার অন্তর্ভুক্ত থাকবে না (যা ভাল জিনিস হতে পারে তবে এটি জানা গুরুত্বপূর্ণ)।
উইসবাকি

shopt -s dotglobওয়াইল্ডকার্ডগুলি প্রসারিত করার সময় আপনি ডটফিলস / ডটডিয়ারগুলি অন্তর্ভুক্ত করতে ব্যবহার করতে পারেন তা লক্ষ করা কার্যকর । আরও দেখুন: gnu.org/software/bash/manual/html_node/The-Shopt- বুলেটিন এইচটিএমএল
স্টেইন

আমার মনে হয় আপনি বোঝানো /*পরিবর্তে */সঙ্গে /পাথ আপনি ব্যবহার করতে চান উপস্থাপন করে।
ব্রুটসর্ফুজথ্রিক্স

2
@ শুলি /*নিখুঁত পথের জন্য হবে যেখানে */বর্তমান অবস্থান থেকে উপ-ডিরেক্টরিগুলি অন্তর্ভুক্ত থাকবে
ড্যান জি

3
সহায়ক ইঙ্গিত: আপনার যদি '/' থেকে $ d থেকে ট্রিলিং করতে হয় তবে ব্যবহার করুন${d%/*}
হাফথর

18

ব্যবহার findকমান্ড ।

জিএনইউতে findআপনি -execdirপ্যারামিটার ব্যবহার করতে পারেন :

find . -type d -execdir realpath "{}" ';'

বা -execপরামিতি ব্যবহার করে :

find . -type d -exec sh -c 'cd -P "$0" && pwd -P' {} \;

বা xargsআদেশ সহ:

find . -type d -print0 | xargs -0 -L1 sh -c 'cd "$0" && pwd && echo Do stuff'

বা ব্যবহার লুপের জন্য :

for d in */; { echo "$d"; }

পুনরাবৃত্তির জন্য এর **/পরিবর্তে প্রসারিত গ্লোববিং ( ) সক্ষম করুন (এর দ্বারা সক্ষম করুন shopt -s extglob)।


আরও উদাহরণের জন্য দেখুন: প্রতিটি ডিরেক্টরিতে গিয়ে কমান্ড কার্যকর করতে কীভাবে? এসও তে


1
-exec {} +POSIX- নির্দিষ্ট, -exec sh -c 'owd=$PWD; for arg; do cd -- "$arg" && pwd -P; cd -- "$owd"; done' _ {} +এটি অন্য আইনী বিকল্প, এবং এর চেয়ে কম শেল আহ্বান করে -exec sh -c '...' {} \;
চার্লস ডাফি

13

হ্যান্ড ওয়ান লাইনার

for D in *; do echo "$D"; done
for D in *; do find "$D" -type d; done ### Option A

find * -type d ### Option B

এর মধ্যে ফাঁকা স্থান সহ ফোল্ডারগুলির জন্য বিকল্প বিকল্পটি সঠিক। এছাড়াও, সাধারণত তাড়াতাড়ি যেহেতু এটি প্রতিটি শব্দ পৃথক সত্ত্বা হিসাবে ফোল্ডারের নামে মুদ্রণ করে না।

# Option A
$ time for D in ./big_dir/*; do find "$D" -type d > /dev/null; done
real    0m0.327s
user    0m0.084s
sys     0m0.236s

# Option B
$ time for D in `find ./big_dir/* -type d`; do echo "$D" > /dev/null; done
real    0m0.787s
user    0m0.484s
sys     0m0.308s

10

find . -type d -print0 | xargs -0 -n 1 my_command


আমি কি লুপের জন্য সেই ফিরতি মানটি খাওয়াতে পারি? এটি একটি বৃহত্তর স্ক্রিপ্টের অংশ ...
মাইকুইলিয়ামসন

@ মাইক, সম্ভাবনা নেই। $? এর চেয়ে সম্ভবত আপনাকে খুঁজে পেতে বা xargs কমান্ডের স্থিতি পেয়ে যাবে my_command
পল টমলিন

7

এটি একটি সাব-শেল তৈরি করবে (যার অর্থ whileলুপটি প্রস্থান করার সময় চলক মানগুলি নষ্ট হয়ে যাবে ):

find . -type d | while read -r dir
do
    something
done

এটি হবে না:

while read -r dir
do
    something
done < <(find . -type d)

ডিরেক্টরি নামগুলির মধ্যে ফাঁকা স্থান উপস্থিত থাকলে উভয়ই কাজ করবে।


অদ্ভুত ফাইলের নামগুলি আরও ভালভাবে পরিচালনা করার জন্য (হোয়াইটস্পেসের সাথে শেষ হওয়া নামগুলি এবং / অথবা লাইনফিড অন্তর্ভুক্ত সহ) ব্যবহার করুন find ... -print0এবংwhile IFS="" read -r -d $'\000' dir
গর্ডন ডেভিসন

@ গর্ডন ডেভিসন, ... সত্যই, আমি এমনকি তর্ক করতে চাইছি যে -d ''বাশ সিনট্যাক্স এবং ক্ষমতা সম্পর্কে কম বিভ্রান্তিকর, যেহেতু -d $'\000'বোঝানো হয়েছে (মিথ্যা) যা $'\000'কোনও উপায়ে ভিন্ন ''indeed প্রকৃতপক্ষে, কেউ সহজেই (এবং আবারও মিথ্যা) এর থেকে অনুমান করতে পারে এটি ব্যাশ সি স্ট্রিংয়ের পরিবর্তে পাস্কাল স্টাইলের স্ট্রিংগুলিকে সমর্থন করে (দৈর্ঘ্য-নির্দিষ্ট, NUL লিটারাল ধারণ করতে সক্ষম) (NUL বিস্মৃত, NULs ধারণ করতে অক্ষম)।
চার্লস ডাফি

5

আপনি চেষ্টা করতে পারেন:

#!/bin/bash
### $1 == the first args to this script
### usage: script.sh /path/to/dir/

for f in `find . -maxdepth 1 -mindepth 1 -type d`; do
  cd "$f"
  <your job here>
done

অথবা সাদৃশ্যপূর্ণ...

ব্যাখ্যা:

find . -maxdepth 1 -mindepth 1 -type d: কেবলমাত্র সর্বাধিক পুনরাবৃত্তিমূলক গভীরতার সাথে ডিরেক্টরিগুলি (কেবলমাত্র sub 1 এর উপ-ডিরেক্টরিগুলি) এবং সর্বনিম্ন 1 এর গভীরতা (বর্তমান ফোল্ডার বাদ দেয় .) সন্ধান করুন


এটি বগি - স্পেস সহ ডিরেক্টরি নামের চেষ্টা করুন। দেখুন BashPitfalls # 1 , এবং DontReadLinesWithFor
চার্লস ডাফি

স্পেস সহ ডিরেক্টরিটির নাম উদ্ধৃতিতে আবদ্ধ এবং কাজ করে এবং ওপি ফাইল থেকে লাইনগুলি পড়ার চেষ্টা করছে না।
হেনরি ডবসন

এটা কাজ করে cd "$f"। যখন আউটপুটটি findস্ট্রিং-বিভক্ত হয় তখন এটি কাজ করে না , সুতরাং আপনার আলাদা আলাদা মান হিসাবে নামের আলাদা আলাদা টুকরো থাকবে $f, আপনি কতটা ভাল করছেন তা তৈরি করে না বা $fসম্প্রসারণের শব্দটির উদ্ধৃতি দেবেন না ।
চার্লস ডাফি

আমি বলিনি তারা ছিল একটি ফাইল থেকে লাইন পড়ার চেষ্টা করার। findডিফল্ট -printক্রিয়া সহ আউটপুটটি লাইন-ভিত্তিক (এক লাইনের এক নাম, তাত্ত্বিকভাবে - তবে নীচে দেখুন) ।
চার্লস ডাফি

লাইন-ওরিয়েন্টেড আউটপুট, যেমন থেকে যথেচ্ছ ফাইল নামগুলি পাস করার নিরাপদ উপায় find -printনয় , যেহেতু কেউ কিছু চালাতে পারে এবং একটি ডিরেক্টরি পেতে পারে যা এর নামে পৃথক লাইন রয়েছে line যত্ন বা ছাড়াই ফাইল বা ডিরেক্টরি থেকে নাম হ্যান্ডেল করা সুবিধা বর্ধনের আক্রমণ পাওয়ার দুর্দান্ত উপায়। mkdir -p $'foo\n/etc/passwd\nbar'/etc/passwd/upload/tmp
চার্লস ডাফি

4

ডিরেক্টরিগুলির নাম থাকলে তা গ্রহণযোগ্য উত্তরটি সাদা স্পেসে বিভক্ত হয়ে যায় এবং পছন্দের বাক্য $()গঠনটি বাশ / ksh এর জন্য হয়। উদাহরণস্বরূপ GNU find -exec বিকল্প ব্যবহার করুন+;

find .... -exec mycommand +; #this is same as passing to xargs

অথবা কিছুক্ষণ লুপ ব্যবহার করুন

find .... |  while read -r D
do
  ...
done 

ডিরেক্টরি নামটি কী ধরে রাখবে? উদাহরণস্বরূপ, chmod + x $ DIR_NAME (হ্যাঁ, আমি জানি কেবল ডিরেক্টরিগুলির জন্য একটি chmod বিকল্প রয়েছে)
মাইক গ্রাফ

find -execএবং পাস করার মধ্যে একটি সূক্ষ্ম পার্থক্য রয়েছে xargs: findকমান্ড কার্যকর হওয়া কমান্ডের প্রস্থান মূল্য অগ্রাহ্য করবে এবং xargsননজারো প্রস্থান করতে ব্যর্থ হবে। হয় আপনার প্রয়োজনের উপর নির্ভর করে সঠিক হতে পারে।
জেসন ওদিকিকা

find ... -print0 | while IFS= read -r dনিরাপদ - এমন নামগুলিকে সমর্থন করে যা শ্বেত স্পেসে শুরু হয় বা শেষ হয় এবং নামগুলিতে নিউলাইন আক্ষরিক থাকে lite
চার্লস ডফি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.