ডিরেক্টরিতে সমস্ত ফাইলের কমান্ড কার্যকর করুন


289

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

উদাহরণস্বরূপ, 1 টি ফাইলে কমান্ড চালাতে:

$ cmd [option] [filename] > results.out

3
আমি প্রশ্ন যুক্ত করতে চাই। এটি কি xargs ব্যবহার করে করা যেতে পারে? যেমন, ls <directory> | xargs cmd [options] {filenames put in here automatically by xargs} [more arguments] > results.out
ওজায়ের কাফরে

2
এটি পারে তবে আপনি সম্ভবত ড্রাইভ ব্যবহারls করতে চান নাxargs । যদি cmdমোটামুটি দক্ষতার সাথে লেখা থাকে তবে সম্ভবত আপনি তা করতে পারেন cmd <wildcard>
ট্রিপলি

উত্তর:


423

নিম্নলিখিত বাশ কোডটি command ফাইলটি কমান্ডে পাস করবে যেখানে $ ফাইল প্রতিটি ফাইলকে / ডায়ারে উপস্থাপন করবে

for file in /dir/*
do
  cmd [option] "$file" >> results.out
done

উদাহরণ

el@defiant ~/foo $ touch foo.txt bar.txt baz.txt
el@defiant ~/foo $ for i in *.txt; do echo "hello $i"; done
hello bar.txt
hello baz.txt
hello foo.txt

23
যদি কোনও ফাইলের মধ্যে উপস্থিত না থাকে /dir/, তবে লুপটি একবারে '*' এর মান দিয়ে চলে তবে এটি $fileঅনাকাঙ্ক্ষিত হতে পারে। এটি এড়াতে, লুপের সময়কালের জন্য নালগ্লোব সক্ষম করুন। লুপের আগে shopt -s nullglobএই লাইনটি এবং লুপের পরে এই লাইনটি যুক্ত করুন shopt -u nullglob #revert nullglob back to it's normal default state
স্টিউ-আউ

43
+1, এবং এটি আমার পুরো ওয়ালপেপার সংগ্রহের জন্য ব্যয় করেছে। আমার পরে সবাই, ডাবলকোট ব্যবহার করুন। "$ ফাইল"
বেহরোজ

যদি আউটপুট ফাইলটি লুপের ভিতরে একই থাকে তবে এটি লুপের বাইরে পুনর্নির্দেশ করা অনেক বেশি দক্ষ done >results.out(এবং সম্ভবত তখন আপনি সংযোজনের পরিবর্তে ওভাররাইট করতে পারবেন, যেমন আমি এখানে ধরে নিয়েছি)।
ট্রিপলি

আপনি কীভাবে স্বতন্ত্র ফলাফলের ফাইলগুলি পাবেন যা তাদের ইনপুট ফাইলগুলিতে কাস্টম নামের রয়েছে?
টিমোথি সোয়ান

1
এই কমান্ডটি ডায়ারে প্রচুর পরিমাণে ফাইলের জন্য ব্যবহার করে যত্নবান হন। পরিবর্তে সন্ধান-এক্সেক ব্যবহার করুন।
কলিস্কো

181

এটি সম্পর্কে:

find /some/directory -maxdepth 1 -type f -exec cmd option {} \; > results.out
  • -maxdepth 1যুক্তি কোনও উপ-ডিরেক্টরিতে পুনরাবৃত্তভাবে অবতরণ থেকে অনুসন্ধানকে বাধা দেয়। (আপনি যদি এমন নেস্টেড ডিরেক্টরিগুলি প্রক্রিয়াজাত করতে চান তবে আপনি এটি বাদ দিতে পারেন))
  • -type -f নির্দিষ্ট করে যে কেবল প্লেইন ফাইলগুলি প্রক্রিয়া করা হবে।
  • -exec cmd option {}এটিকে প্রতিটি ফাইলের জন্য cmdনির্দিষ্ট optionফাইলটির সাথে ফাইল ফাইলের পরিবর্তে চালিত হতে বলে{}
  • \; কমান্ডের শেষ নির্দেশ করে।
  • অবশেষে, সমস্ত পৃথক cmdমৃত্যুদণ্ড কার্যকর করা থেকে আউটপুট পুনঃনির্দেশিত হয় results.out

তবে, যদি আপনি ফাইলগুলি যে ক্রমে প্রক্রিয়াজাত হয় সেটির বিষয়ে যত্নশীল হন তবে লুপটি লেখার চেয়ে আপনি আরও ভাল be আমি মনে করি findফাইলগুলি ইনোড ক্রমে প্রক্রিয়া করা হয় (যদিও আমি সে সম্পর্কে ভুল হতে পারি), যা আপনি চান তা নাও হতে পারে।


1
এটি ফাইলগুলি প্রক্রিয়া করার সঠিক উপায়। লুপের জন্য ব্যবহার করা অনেক কারণে ত্রুটি-প্রবণ। এছাড়াও বাছাই করা যেমন অন্যান্য কমান্ডগুলি ব্যবহার করে statএবং sortকী কী অবশ্যই অবশ্যই বাছাইয়ের মানদণ্ডের উপর নির্ভর করে।
tuxdna

1
আমি যদি দুটি কমান্ড চালাতে চাই তবে -execবিকল্পগুলির পরে আমি কীভাবে তাদের লিঙ্ক করব ? আমি কি তাদের একক উদ্ধৃতি বা অন্য কিছুতে গুটিয়ে রাখতে পারি?
frei

findসর্বদা সেরা বিকল্প কারণ হিসাবে আপনি বিকল্পের সাথে ফাইলের নাম ধরণ দ্বারা ফিল্টার -nameকরতে পারেন এবং আপনি এটি একটি একক কমান্ডে করতে পারেন।
জোও পিমেন্টেল

3
@frei আপনার প্রশ্নের উত্তর এখানে: stackoverflow.com/a/6043896/1243247 কিন্তু মূলত শুধু যোগ -execবিকল্পগুলি:find . -name "*.txt" -exec echo {} \; -exec grep banana {} \;
জোয়াও মধ্যে Pimentel ফেরেইরা

2
বিকল্প হিসাবে আপনি ফাইলের নামটি কীভাবে উল্লেখ করতে পারেন?
তোসকান

54

আমি চালিয়ে কমান্ড লাইন থেকে আমার রাস্পবেরি পাইতে এটি করছি:

for i in *;do omxplayer "$i";done

7

গৃহীত / উচ্চ-ভোট প্রাপ্ত উত্তরগুলি দুর্দান্ত, তবে সেগুলিতে কয়েকটি অদ্ভুত-বিব্রত বিশদের অভাব রয়েছে। শেল পাথ-নাম সম্প্রসারণ (গ্লোব) ব্যর্থ হয়, যখন ফাইলের নামগুলি এমবেড করা নিউলাইন / ড্যাশ প্রতীক ধারণ করে এবং কমান্ড আউটপুটটিকে লুপের বাইরে পুনঃনির্দেশকে সরিয়ে নিয়ে ফলাফল লেখার সময় কীভাবে পরিচালনা করতে হয় তার ক্ষেত্রে এই পোস্টটি অন্তর্ভুক্ত করে covers ফাইল।

যখন ব্যবহার শেল উল্লিখিত glob সম্প্রসারণ চলমান *সেখানে যদি আছে সম্প্রসারণ ব্যর্থ করার জন্য একটি সম্ভাবনা আছে কোন ফাইল ডিরেক্টরি ও একটি অ-প্রসারিত উল্লিখিত glob স্ট্রিং উপস্থিত কমান্ড চালানো যাবে, যা অবাঞ্ছিত ফলাফল হতে পারে প্রেরণ করা হবে না। bashশেল এই ব্যবহারের জন্য একটি বর্ধিত শেল বিকল্প প্রদান করে nullglob। সুতরাং লুপটি মূলত আপনার ফাইলগুলি সম্বলিত ডিরেক্টরিতে অন্তর্ভুক্ত হয়

 shopt -s nullglob

 for file in ./*; do
     cmdToRun [option] -- "$file"
 done

এক্সপ্রেশন ./*কোনও ফাইল ফেরত না দেয় এটি আপনাকে নিরাপদে লুপের জন্য প্রস্থান করতে দেয় (ডিরেক্টরিটি ফাঁকা থাকলে)

বা POSIX অনুবর্তী ভাবে ( nullglobহয় bashনির্দিষ্ট)

 for file in ./*; do
     [ -f "$file" ] || continue
     cmdToRun [option] -- "$file"
 done

এক্সপ্রেশন একবারে ব্যর্থ হয়ে যায় এবং শর্তটি [ -f "$file" ]পরীক্ষা না করে অন-প্রসারিত স্ট্রিংটি ./*সেই ডিরেক্টরিতে কোনও বৈধ ফাইলের নাম কিনা এটি আপনাকে লুপের ভিতরে যেতে দেয় which সুতরাং এই শর্তে ব্যর্থতা ব্যবহার করে continueআমরা আবার লুপটিতে আবার শুরু করি forযা পরবর্তী সময়ে চলবে না।

--ফাইল নামের যুক্তিটি পাস করার ঠিক আগে ব্যবহারের বিষয়টিও নোট করুন । এটি প্রয়োজন কারণ পূর্বে উল্লিখিত হিসাবে, শেল ফাইলের নামগুলিতে ফাইলের যে কোনও জায়গায় ড্যাশ থাকতে পারে। শেল কমান্ডগুলির মধ্যে কিছু এটি ব্যাখ্যা করে এবং নামটি সঠিকভাবে উদ্ধৃত না করা হলে কমান্ড বিকল্প হিসাবে তাদের আচরণ করে এবং পতাকা সরবরাহ করা হয় কিনা তা ভেবে কমান্ডটি কার্যকর করে।

--সংকেত যে ক্ষেত্রে যা অর্থ হলো কমাণ্ড লাইন অপশন সম্বন্ধে শেষ, আদেশ কমান্ড পতাকা হিসাবে এই বিন্দু অতিক্রম কিন্তু শুধুমাত্র ফাইলের নামের কোন পংক্তি সঠিকরূপে মীমাংসা করা উচিত নয়।


যখন নামগুলি গ্লোব অক্ষর বা সাদা স্পেস থাকে তখন ফাইলের নামগুলি ডাবল-কোট করা সঠিকভাবে কেসগুলি সমাধান করে। তবে * নিক্স ফাইলের নামগুলিতে সেগুলিতে নতুন লাইনও থাকতে পারে। সুতরাং আমরা ফাইলের নামগুলি কেবলমাত্র অক্ষর দিয়ে সীমিত করি যা কোনও বৈধ ফাইল নামের অংশ হতে পারে না - নাল বাইট ( \0)। যেহেতু bashঅভ্যন্তরীণভাবে Cস্টাইলের স্ট্রিংগুলি ব্যবহার করা হয় যেখানে নাল বাইটগুলি স্ট্রিংয়ের সমাপ্তি নির্দেশ করতে ব্যবহৃত হয়, এটি এটির জন্য সঠিক প্রার্থী।

সুতরাং কমান্ডের বিকল্পটি printfব্যবহার করে এই নুল বাইট দিয়ে ফাইলগুলি সীমিত করতে শেলের বিকল্পটি ব্যবহার করে , আমরা নীচে করতে পারি-dread

( shopt -s nullglob; printf '%s\0' ./* ) | while read -rd '' file; do
    cmdToRun [option] -- "$file"
done

nullglobএবং printfপ্রায় আবৃত করা হয় (..), যার মানে তারা মূলত একটি উপ-শেল (শিশু শেল) চালানোর কারণ এড়াতে nullglobএকবার কমান্ড প্রস্থান করে, পিতা বা মাতা শেল নিয়ে গভীরভাবে চিন্তা করার বিকল্প। -d ''বিকল্প readকমান্ড না POSIX অনুবর্তী, তাই একটি প্রয়োজন bashশেল এই কাজ করা জন্য। findকমান্ড ব্যবহার করে এটি করা যায়

while IFS= read -r -d '' file; do
    cmdToRun [option] -- "$file"
done < <(find -maxdepth 1 -type f -print0)

যে findবাস্তবায়নগুলি সমর্থন করে না -print0(জিএনইউ এবং ফ্রিবিএসডি বাস্তবায়ন ব্যতীত), এটি ব্যবহার করে অনুকরণ করা যেতে পারেprintf

find . -maxdepth 1 -type f -exec printf '%s\0' {} \; | xargs -0 cmdToRun [option] --

আর একটি গুরুত্বপূর্ণ ফিক্স হ'ল ফাইলের I / O এর একটি উচ্চ সংখ্যা হ্রাস করার জন্য পুনরায় দিকটি লুপের বাইরে নিয়ে যাওয়া। লুপটির অভ্যন্তরে ব্যবহৃত হলে, শেলটি ফর-লুপের প্রতিটি পুনরাবৃত্তির জন্য দুবার সিস্টেম কল প্রয়োগ করতে হবে, একবার খোলার জন্য এবং একবার ফাইলের সাথে সম্পর্কিত ফাইল বিবরণকারী বন্ধ করার জন্য। এটি বড় পুনরাবৃত্তিগুলি চালানোর জন্য আপনার পারফরম্যান্সের বোতল-ঘাড়ে পরিণত হবে। প্রস্তাবিত পরামর্শ হ'ল এটিকে লুপের বাইরে নিয়ে যাওয়া।

এই সংশোধনগুলি সহ উপরের কোডটি প্রসারিত করা, আপনি করতে পারেন

( shopt -s nullglob; printf '%s\0' ./* ) | while read -rd '' file; do
    cmdToRun [option] -- "$file"
done > results.out

যা মূলত আপনার ফাইলের ইনপুটটির প্রতিটি পুনরাবৃত্তির জন্য স্ট্যান্ডআউটে আপনার আদেশের বিষয়বস্তু রাখবে এবং যখন লুপটি শেষ হবে, স্ট্যাডআউটের বিষয়বস্তু লিখতে এবং সংরক্ষণ করার জন্য লক্ষ্য ফাইলটি একবার খুলুন। findএকই সমতুল্য সংস্করণ হবে

while IFS= read -r -d '' file; do
    cmdToRun [option] -- "$file"
done < <(find -maxdepth 1 -type f -print0) > results.out

1
ফাইলটি আছে কিনা তা পরীক্ষা করার জন্য +1। যদি অস্তিত্বহীন দিরের সন্ধান করা হয় তবে $ ফাইলটিতে বৈধ ফাইলের নাম নয় "রেভেক্স স্ট্রিং" / ইনভাল্ড_ডির / * "থাকে।
সিডিএলএক্সেন্ডার

1
এটি গ্রহণযোগ্য উত্তর হওয়া উচিত।
nnov

3

একটি দ্রুত এবং নোংরা উপায় যা কাজটি কখনও কখনও সম্পন্ন করে তা হ'ল:

find directory/ | xargs  Command 

উদাহরণস্বরূপ বর্তমান ডিরেক্টরিতে সমস্ত ফাইলে লাইন সংখ্যা সন্ধান করার জন্য আপনি এটি করতে পারেন:

find . | xargs wc -l

8
@ হুবার্ট আপনার ফাইলনামগুলিতে কেন নতুন লাইন ??
musicin3d

2
এটি "কেন" এর প্রশ্ন নয়, এটি নির্ভুলতার একটি প্রশ্ন - ফাইলের নামগুলিতে মুদ্রণযোগ্য অক্ষরগুলি অন্তর্ভুক্ত করতে হবে না, তাদের বৈধ ইউটিএফ -8 সিকোয়েন্সও থাকতে হবে না। এছাড়াও, একটি নতুনলাইন কী খুব বেশি এনকোডিং নির্ভর, একটি এনকোডিং ings অন্যটির নতুন লাইন। কোড পৃষ্ঠা 437 দেখুন
হুবার্ট কারিও

2
সিমন, সত্যি? এটি সময়ের 99.9% কাজ করে এবং তিনি "দ্রুত এবং নোংরা" বলেছেন
এডোয়ার্ডো

আমি "কুইক অ্যান্ড নোংরা" (একেএ "ভাঙ্গা") বাশ স্ক্রিপ্টগুলির ভক্ত নই। যত তাড়াতাড়ি বা পরে এটি বিখ্যাত "মুভিড ~/.local/share/steam। রান স্টিমের মতো জিনিসে শেষ হয় It এটি ব্যবহারকারীর মালিকানাধীন সিস্টেমে সমস্ত কিছু মুছে ফেলে।" বাগ রিপোর্ট।
ক্রিয়াকলাপ হ্রাস

এটি নামের জায়গাগুলি থাকা ফাইলগুলির সাথেও কাজ করবে না।
শামাস এস - মনিকা পুনরায়

2

আমার সমস্ত .md ফাইলগুলি একটি ডিরেক্টরি থেকে অন্য ডিরেক্টরিতে অনুলিপি করা দরকার ছিল, তাই আমি এখানে যা করেছি তা এখানে।

for i in **/*.md;do mkdir -p ../docs/"$i" && rm -r ../docs/"$i" && cp "$i" "../docs/$i" && echo "$i -> ../docs/$i"; done

যা পড়া খুব কঠিন, তাই এটি ভেঙে দেওয়া যাক।

আপনার ফাইলগুলির সাথে ডিরেক্টরিতে প্রথম সিডি করুন,

for i in **/*.md; আপনার প্যাটার্ন প্রতিটি ফাইলের জন্য

mkdir -p ../docs/"$i"আপনার ফাইল ধারণকারী ফোল্ডারের বাইরে কোনও ডকস ফোল্ডারে সেই ডিরেক্টরিটি তৈরি করুন। যা সেই ফাইলটির মতো একই নামে একটি অতিরিক্ত ফোল্ডার তৈরি করে।

rm -r ../docs/"$i" ফলে তৈরি হওয়া অতিরিক্ত ফোল্ডারটি সরিয়ে ফেলুন mkdir -p

cp "$i" "../docs/$i" আসল ফাইলটি অনুলিপি করুন

echo "$i -> ../docs/$i" আপনি যা করেছেন তা প্রতিধ্বনি করুন

; done কখনও পরে সুখে বাস


দ্রষ্টব্য: **কাজ করার জন্য, globstarশেল বিকল্পটি সেট করা দরকার:shopt -s globstar
হুবার্ট কারিও

2

তুমি ব্যবহার করতে পার xarg

ls | xargs -L 1 -d '\n' your-desired-command

-L 1 একসাথে 1 আইটেম পাস করে

-d '\n'মেক আউটপুট lsনতুন লাইনের উপর ভিত্তি করে বিভক্ত হয়।


1

@ জিম লুইসের পদ্ধতির ভিত্তিতে:

এখানে তাদের সমাধানের findতারিখ অনুসারে ফাইলগুলি বাছাই করার জন্য একটি দ্রুত সমাধান রয়েছে :

$ find  directory/ -maxdepth 1 -type f -print0 | \
  xargs -r0 stat -c "%y %n" | \
  sort | cut -d' ' -f4- | \
  xargs -d "\n" -I{} cmd -op1 {} 

বাছাইয়ের জন্য দেখুন:

http://www.commandlinefu.com/commands/view/5720/find-files-and-list-them-sorted-by-modification-time


ফাইলগুলির নামগুলিতে নতুন লাইন থাকলে এই কাজ করবে না
হুবার্ট কারিও

1
@HubertKario আপনি সম্পর্কে আরও পড়তে পারেন -print0জন্য findএবং -0জন্য xargs(নতুন লাইন সহ) কোন হোয়াইটস্পেস পরিবর্তে নাল অক্ষর ব্যবহার করে।
tuxdna

হ্যাঁ, ব্যবহার -print0হ'ল এমন কিছু যা সহায়তা করে তবে পুরো পাইপলাইনটি এর মতো কিছু ব্যবহার করা দরকার এবং sortতা নয়
হুবার্ট কারিও

1

আমি মনে করি সহজ সমাধানটি হ'ল:

sh /dir/* > ./result.txt

2
আপনি প্রশ্নটি সঠিকভাবে বুঝতে পেরেছিলেন? এটি কেবল প্রতিটি শেলের মাধ্যমে ডিরেক্টরিতে প্রতিটি ফাইল চালানোর চেষ্টা করবে - যেন এটি কোনও স্ক্রিপ্ট।
rdas

1

সর্বোচ্চ গভীরতা

আমি দেখতে পেয়েছি এটি জিম লুইসের উত্তরের সাথে দুর্দান্তভাবে কাজ করে কেবল কিছুটা যুক্ত করুন:

$ export DIR=/path/dir && cd $DIR && chmod -R +x *
$ find . -maxdepth 1 -type f -name '*.sh' -exec {} \; > results.out

বাছাই অর্ডার

আপনি যদি বাছাই ক্রমে সম্পাদন করতে চান তবে এটিকে এভাবে সংশোধন করুন:

$ export DIR=/path/dir && cd $DIR && chmod -R +x *
find . -maxdepth 2 -type f -name '*.sh' | sort | bash > results.out

উদাহরণস্বরূপ, এটি নিম্নলিখিত আদেশ সহ কার্যকর করা হবে:

bash: 1: ./assets/main.sh
bash: 2: ./builder/clean.sh
bash: 3: ./builder/concept/compose.sh
bash: 4: ./builder/concept/market.sh
bash: 5: ./builder/concept/services.sh
bash: 6: ./builder/curl.sh
bash: 7: ./builder/identity.sh
bash: 8: ./concept/compose.sh
bash: 9: ./concept/market.sh
bash: 10: ./concept/services.sh
bash: 11: ./product/compose.sh
bash: 12: ./product/market.sh
bash: 13: ./product/services.sh
bash: 14: ./xferlog.sh

সীমাহীন গভীরতা

আপনি যদি কিছু শর্ত দ্বারা সীমাহীন গভীরতায় চালিত করতে চান তবে আপনি এটি ব্যবহার করতে পারেন:

export DIR=/path/dir && cd $DIR && chmod -R +x *
find . -type f -name '*.sh' | sort | bash > results.out

তারপরে বাচ্চাদের ডিরেক্টরিগুলির মধ্যে প্রতিটি ফাইলের উপরে এটি রাখুন:

#!/bin/bash
[[ "$(dirname `pwd`)" == $DIR ]] && echo "Executing `realpath $0`.." || return

এবং কোথাও পিতামাতার ফাইলের শৃঙ্খলে:

if <a condition is matched>
then
    #execute child files
    export DIR=`pwd`
fi
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.