কিভাবে প্রতিটি ডিরেক্টরিতে গিয়ে কমান্ড কার্যকর করা যায়?


143

আমি একটি ব্যাশ স্ক্রিপ্ট করে একটি parent_directory ভিতরে প্রতিটি ডিরেক্টরির মাধ্যমে যায় এবং কিভাবে লিখুন executes একটি কমান্ড মধ্যে প্রতিটি ডিরেক্টরির

ডিরেক্টরি কাঠামোটি নিম্নরূপ:

প্যারেন্ট_ডাইরেক্টরি (নাম কিছু হতে পারে - একটি প্যাটার্ন অনুসরণ করে না)

  • 001 (ডিরেক্টরি নামগুলি এই ধরণটি অনুসরণ করে)
    • 0001.txt (ফাইলের নামগুলি এই ধরণটি অনুসরণ করে)
    • 0002.txt
    • 0003.txt
  • 002
    • 0001.txt
    • 0002.txt
    • 0003.txt
    • 0004.txt
  • ২003
    • 0001.txt

ডিরেক্টরি সংখ্যা অজানা।

উত্তর:


108

আপনার বর্তমান ডিরেক্টরিটি যখন আপনি নিম্নলিখিতটি করতে পারেন parent_directory:

for d in [0-9][0-9][0-9]
do
    ( cd "$d" && your-command-here )
done

(এবং ), একটি subshell তৈরি তাই বর্তমান ডিরেক্টরী প্রধান লিপিতে পরিবর্তন হয় নি।


5
এখানে ব্যাপারটি গুরুত্বপূর্ণ নয় কারণ ওয়াইল্ডকার্ড সংখ্যার চেয়ে অন্য কোনও কিছুর সাথে মেলে না, তবে সাধারণ ক্ষেত্রে আপনি মূলত সর্বদা ডিরেক্টরিটির নামটি লুপের ভিতরে ডাবল উদ্ধৃতিতে রাখতে চান। cd "$d"এটি আরও ভাল হয় যে এটি এমন পরিস্থিতিতে স্থানান্তর করে যেখানে ওয়াইল্ডকার্ড ফাইলগুলির সাথে মেলে যাঁদের নামের সাথে শ্বেতস্পেস এবং / অথবা শেল মেটাচার্যাক্টর রয়েছে।
ট্রিপলি

1
(এখানে থাকা সমস্ত উত্তরগুলির মধ্যে একই ত্রুটি রয়েছে বলে মনে হয় তবে এটি শীর্ষ-ভোট প্রাপ্ত উত্তরের মধ্যে সবচেয়ে বেশি গুরুত্বপূর্ণ))
ট্রিপলি

1
এছাড়াও, সর্বাধিক কমান্ডগুলি কোন ডিরেক্টরিতে আপনি সেগুলি সম্পাদন করেন সে বিষয়ে আসলে চিন্তা করে না। for f in foo bar; do cat "$f"/*.txt; done >outputকার্যত সমতুল্য cat foo/*.txt bar/*.txt >output। তবে, lsএকটি কমান্ড হ'ল আপনি এটি কীভাবে যুক্তিটি পাস করবেন তার উপর নির্ভর করে কিছুটা আলাদা আউটপুট তৈরি করে; একইভাবে, যা grepবা wcকোনও আপেক্ষিক ফাইলের নাম আউটপুট দেয় আপনি যদি তা উপ-ডিরেক্টরি থেকে চালান তবে (তবে প্রায়শই আপনি সেই কারণে সংক্ষিপ্তভাবে সাব-ডাইরেক্টরিতে যাওয়া এড়াতে চান)।
ট্রিপলি

158

টড পোস্ট করা এই উত্তরটি আমাকে সাহায্য করেছিল।

find . -maxdepth 1 -type d \( ! -name . \) -exec bash -c "cd '{}' && pwd" \;

\( ! -name . \) এড়াতে বর্তমান ডিরেক্টরির মধ্যে কমান্ড নির্বাহ।


4
এবং যদি আপনি কেবল নির্দিষ্ট ফোল্ডারে কমান্ডটি চালাতে চান:find FOLDER* -maxdepth 0 -type d \( ! -name . \) -exec bash -c "cd '{}' && pwd" \;
মার্টিন কে

3
আমাকে -exec bash -c 'cd "$0" && pwd' {} \;কিছু করতে হয়েছিল যেহেতু কিছু ডিরেক্টরিতে একক উদ্ধৃতি এবং কিছু ডাবল উদ্ধৃতি রয়েছে।
চার্লি গরিচানাজ

12
আপনি বর্তমান ডিরেক্টরিটি বাদ দিয়েও করতে পারেন-mindepth 1
mdziob

কীভাবে এটি কোনও ফাংশনে পরিবর্তন করবেন pwdসরাসরি "গিট রিমোট গেট-ইউআরএল উত্সের মতো কমান্ড গ্রহণ করুন ?
রোছসনাই

disd(){find . -maxdepth 1 -type d \( ! -name . \) -exec bash -c 'cd "{}" && "$@"' \;}কাজ করে না.
রোচসনই

48

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

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

বা ( @gniourf_gniourf মন্তব্য অনুসারে ):

find . -type d -execdir sh -c 'printf "%s/%s\n" "$PWD" "$0"' {} \;

দ্রষ্টব্য: আপনি সামনের দিকে ঠিক করার ${0#./}পরিবর্তে ব্যবহার করতে পারেন ।$0./

বা আরও ব্যবহারিক উদাহরণ:

find . -name .git -type d -execdir git pull -v ';'

আপনি যদি বর্তমান ডিরেক্টরি অন্তর্ভুক্ত করতে চান তবে এটি ব্যবহার করে আরও সহজ -exec:

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

বা ব্যবহার xargs:

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

বা অনুরূপ উদাহরণ @gniourf_gniourf দ্বারা প্রস্তাবিত :

find . -type d -print0 | while IFS= read -r -d '' file; do
# ...
done

উপরোক্ত উদাহরণগুলি তাদের নামে স্পেস সহ ডিরেক্টরিগুলি সমর্থন করে।


বা ব্যাশ অ্যারেতে বরাদ্দ করে:

dirs=($(find . -type d))
for dir in "${dirs[@]}"; do
  cd "$dir"
  echo $PWD
done

.আপনার নির্দিষ্ট ফোল্ডারের নাম পরিবর্তন করুন । আপনার যদি পুনরাবৃত্তভাবে চালনার দরকার না হয় তবে আপনি এর dirs=(*)পরিবর্তে ব্যবহার করতে পারেন । উপরের উদাহরণটি নামের ফাঁকা জায়গায় ডিরেক্টরিগুলি সমর্থন করে না।

সুতরাং @gniourf_gniourf এর পরামর্শ অনুসারে, স্পষ্ট লুপটি ব্যবহার না করে সন্ধানের আউটপুটটি অ্যারেতে রাখার একমাত্র সঠিক উপায়টি 4.4 বাশনের সাথে পাওয়া যাবে:

mapfile -t -d '' dirs < <(find . -type d -print0)

বা প্রস্তাবিত উপায় নয় (যার মধ্যে পার্সিংls অন্তর্ভুক্ত ):

ls -d */ | awk '{print $NF}' | xargs -n1 sh -c 'cd $0 && pwd && echo Do stuff'

উপরের উদাহরণটি বর্তমান দিরকে উপেক্ষা করবে (ওপি দ্বারা অনুরোধ করা হয়েছে), তবে এটি ফাঁকা জায়গাগুলির সাথে নাম ভাঙবে।

আরো দেখুন:


1
findসুস্পষ্ট লুপ ব্যবহার না করে বিন্যাসে আউটপুট রাখার একমাত্র সঠিক উপায় বাশ 4.4 এর সাথে পাওয়া যাবে mapfile -t -d '' dirs < <(find . -type d -print0)। ততক্ষণে আপনার একমাত্র বিকল্প হ'ল লুপ ব্যবহার করা (বা অপারেশনটি স্থগিত করা find)।
gniourf_gniourf

1
আসলে, আপনার আসলে dirsঅ্যারের দরকার নেই ; আপনি করতে পারে লুপ findএর আউটপুট (নিরাপদে) যেমন: find . -type d -print0 | while IFS= read -r -d '' file; do ...; done
gniourf_gniourf

@gniourf_gniourf আমি ভিজ্যুয়াল এবং সর্বদা চেষ্টা করি যা সহজ দেখায় এমন জিনিসগুলি সন্ধান / তৈরি করার চেষ্টা করে। যেমন আমি এই স্ক্রিপ্টটি করেছি এবং ব্যাশ অ্যারে ব্যবহার করে আমার পক্ষে সহজ এবং পঠনযোগ্য (পাইপ ব্যবহারের পরিবর্তে যুক্তিটিকে ছোট ছোট টুকরো টুকরো করে আলাদা করে)। অতিরিক্ত পাইপ পেশ করা হচ্ছে, IFS, read, এটা অতিরিক্ত জটিলতা ছাপ দেয়। আমি এটি সম্পর্কে চিন্তা করতে হবে, সম্ভবত এটি করার কিছু সহজ উপায় আছে।
কেনোরব

যদি সহজভাবে আপনি ভাঙা বোঝাচ্ছেন তবে হ্যাঁ, করার সহজ উপায় রয়েছে। এখন চিন্তা করবেন না, এগুলি IFSএবং read(যেমন আপনি বলছেন) আপনি যেমন অভ্যস্ত হয়ে উঠেন তখন এটি দ্বিতীয় প্রকৃতিতে পরিণত হয়… এগুলি স্ক্রিপ্টগুলি লেখার প্রচলিত ও মূর্তিযুক্ত পদ্ধতির অংশ।
gniourf_gniourf

যাইহোক, আপনার প্রথম কমান্ড find . -type d -execdir echo $(pwd)/{} ';'আপনি যা চান তা করেন না ( $(pwd)পূর্বে প্রসারিত findএমনকি কার্যকর করা হয়) ...
gniourf_gniourf

29

আপনি পাইপিং এবং তারপরে ব্যবহার করে এটি অর্জন করতে পারেন xargs। ক্যাচটি হ'ল আপনার -Iপতাকাটি ব্যবহার করা দরকার যা আপনার বাশ কমান্ডের স্ট্রিংগুলিকে প্রতিটির দ্বারা পাস করা স্ট্রিংয়ের সাথে প্রতিস্থাপন করবে xargs

ls -d */ | xargs -I {} bash -c "cd '{}' && pwd"

আপনি pwdপ্রতিটি ডিরেক্টরিতে যে কমান্ড চালাতে চান তা দিয়ে প্রতিস্থাপন করতে পারেন।


2
আমি জানি না কেন এটি আপত্তি করা হয়নি, তবে আমি এখনও পর্যন্ত খুঁজে পেয়েছি সবচেয়ে সহজ স্ক্রিপ্ট। ধন্যবাদ
লিনভি

20

টপলেভেল ফোল্ডারটি জানা থাকলে আপনি এই জাতীয় কিছু লিখতে পারেন:

for dir in `ls $YOUR_TOP_LEVEL_FOLDER`;
do
    for subdir in `ls $YOUR_TOP_LEVEL_FOLDER/$dir`;
    do
      $(PLAY AS MUCH AS YOU WANT);
    done
done

এ $ (আপনি যেমন চান তেমন খেলুন); আপনি যত খুশি কোড রাখতে পারেন

মনে রাখবেন যে আমি কোনও ডিরেক্টরিতে "সিডি" করিনি।

চিয়ার্স,


3
সেখানে দৃষ্টান্ত একটি দম্পতি আছে "এর বেহুদা ব্যবহারের ls" এখানে - আপনি অবশ্য কাজ করতে পারে for dir in $YOUR_TOP_LEVEL_FOLDER/*পরিবর্তে।
লংগায়ারকে

1
ওয়েল, সম্ভবত এটি সাধারণ অর্থে অকেজো তবে এটি সরাসরি ফিল্টারিং করতে দেয় ls (অর্থাৎ সমস্ত ডিরেক্টরি .tmp দিয়ে শেষ হয়েছে)। এটা কেন আমি ব্যবহৃত ls $dirঅভিব্যক্তি
gforcada


6

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

#!/bin/bash

#Use set -x if you want to echo each command while getting executed
#set -x

#Save current directory so we can restore it later
cur=$PWD
#Save command line arguments so functions can access it
args=("$@")

#Put your code in this function
#To access command line arguments use syntax ${args[1]} etc
function dir_command {
    #This example command implements doing git status for folder
    cd $1
    echo "$(tput setaf 2)$1$(tput sgr 0)"
    git tag -a ${args[0]} -m "${args[1]}"
    git push --tags
    cd ..
}

#This loop will go to each immediate child and execute dir_command
find . -maxdepth 1 -type d \( ! -name . \) | while read dir; do
   dir_command "$dir/"
done

#This example loop only loops through give set of folders    
declare -a dirs=("dir1" "dir2" "dir3")
for dir in "${dirs[@]}"; do
    dir_command "$dir/"
done

#Restore the folder
cd "$cur"

5

আপনি ফাইলটি তৈরির সাথে বিন্দুটি পাই না, যেহেতু আপনি কেবল ফোল্ডারগুলির মাধ্যমে পুনরাবৃত্তি করতে চান ... আপনি কি এরকম কিছু খুঁজছেন?

cd parent
find . -type d | while read d; do
   ls $d/
done

4

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

find .

বর্তমান ডিরেক্টরি পুনরুক্তিতে সমস্ত ফাইল / ডায়ার সন্ধান করতে

আপনি যেমন xargs কমান্ড আউটপুট পাইপ করতে পারেন

find . | xargs 'command here'

3
এটি জিজ্ঞাসা করা হয় না।
কেনারব

0
for p in [0-9][0-9][0-9];do
    (
        cd $p
        for f in [0-9][0-9][0-9][0-9]*.txt;do
            ls $f; # Your operands
        done
    )
done

আপনাকে আবার ডিরেক্টরিটি ব্যাক আপ করতে হবে, বা cdএকটি সাব-শেল করতে হবে।
মার্ক লংগায়ার

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