ডিরেক্টরিতে ফাইলগুলি কীভাবে লুপ করবেন এবং পথ পরিবর্তন করবেন এবং ফাইলের নামের সাথে প্রত্যয় যুক্ত করুন


562

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

./MyProgram.exe Data/data1.txt [Logs/data1_Log.txt]

আমি যা করতে চাই তার জন্য সিউডোকোডটি এখানে:

for each filename in /Data do
  for int i = 0, i = 3, i++
    ./MyProgram.exe Data/filename.txt Logs/filename_Log{i}.txt
  end for
end for

সুতরাং আমি প্রথমটি থেকে দ্বিতীয় যুক্তিটি কীভাবে তৈরি করব তা আমি সত্যিই বিস্মিত হয়েছি, সুতরাং এটি দেখতে এএবিডি_সিডি_লগ 1.txt এর মতো দেখায় এবং আমার প্রোগ্রামটি শুরু করে।

উত্তর:


736

প্রথমে কয়েকটি নোট: আপনি যখন Data/data1.txtযুক্তি হিসাবে ব্যবহার করেন, তা কি সত্যই হওয়া উচিত /Data/data1.txt(শীর্ষস্থানীয় স্ল্যাশ সহ)? এছাড়াও, বাইরের লুপটি কেবলমাত্র টেক্সট ফাইলগুলির জন্য বা ডেটাতে থাকা সমস্ত ফাইলের জন্যই স্ক্যান করা উচিত? এখানে একটি উত্তর দেওয়া হয়েছে, ধরে নেওয়া /Data/data1.txtএবং কেবল টেক্সট ফাইলগুলি:

#!/bin/bash
for filename in /Data/*.txt; do
    for ((i=0; i<=3; i++)); do
        ./MyProgram.exe "$filename" "Logs/$(basename "$filename" .txt)_Log$i.txt"
    done
done

মন্তব্য:

  • /Data/*.txt/ ডেটাতে ( / ডেটা / অংশ সহ ) পাঠ্য ফাইলগুলির পাথগুলিতে প্রসারিত হয়
  • $( ... ) শেল কমান্ড চালায় এবং কমান্ড লাইনের সেই সময়ে তার আউটপুট সন্নিবেশ করায়
  • basename somepath .txtশেষ থেকে টেক্সট সরানো (যেমন /Data/file.txt-> file) এর সাথে সাম্পাথের বেস অংশটি আউটপুট করে

যদি এর Data/file.txtপরিবর্তে আপনার মাইপ্রোগ্রাম চালানোর দরকার হয় তবে নেতৃস্থানীয় স্ল্যাশ সরিয়ে ফেলতে /Data/file.txtব্যবহার করুন "${filename#/}"। অন্যদিকে, যদি এটি সত্যিই আপনি স্ক্যান করতে চান Dataনা /Data, কেবল ব্যবহার করুন for filename in Data/*.txt


1
দৃশ্যত basename -sএকটি মানহীন এক্সটেনশন - আমি মানক সিনট্যাক্সটি ব্যবহার করার জন্য আমার উত্তরটি সম্পাদনা করব।
গর্ডন ডেভিসন

21
যদি কোনও ফাইল পাওয়া না যায় / ওয়াইল্ডকার্ডের সাথে মেলে না আমি লুপগুলি কার্যকর করতে চাইছি ব্লকটি এখনও ফাইলের নাম = "/ ডেটা /*.txt" দিয়ে প্রবেশ করানো হয়েছে। আমি কীভাবে এড়াতে পারি?
অলিভার পিয়ারমাইন

20
@ অলিভার পিয়ারমাইন হয় shopt -s nullglobলুপের আগে ব্যবহার করুন (এবং shopt -u nullglobপরে সমস্যাগুলি এড়াতে পরে) বা if [[ ! -e "$filename ]]; then continue; fiলুপের শুরুতে যুক্ত করুন , সুতরাং এটি অস্তিত্বযুক্ত ফাইলগুলি এড়িয়ে যাবে।
গর্ডন ডেভিসন

9
যখন তাদের নামে সাদা জায়গা আছে এমন ফাইলগুলি থাকে তখন এটি কাজ করে না।
যিশা হাসেন

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

344

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

উদাহরণ স্বরূপ:

for filename in Data/*.txt; do
    [ -e "$filename" ] || continue
    # ... rest of the loop body
done

তথ্যসূত্র: বাশ পিটফলস


8
এটি এখনও একটি সময়োচিত সতর্কতা। আমি ভেবেছিলাম যে আমি আমার স্ক্রিপ্টটি ভুলভাবে তৈরি করেছি, তবে আমার ফাইলের এক্সটেনশন লোয়ার কেসের পরিবর্তে বড় হাতের অক্ষর রয়েছে, এটিতে কোনও ফাইল পাওয়া যায় নি, এবং গ্লোব প্যাটার্নটি ফিরে এসেছে। বিতৃষ্ণা।
রুফাসভিএস

5
যেহেতু ব্যাশ ট্যাগটি ব্যবহার করা হয়েছে: এটাই তার shopt nullglobজন্য! (বা shopt failglobআপনার ব্যবহারের উপর নির্ভর করে খুব ব্যবহার করা যেতে পারে)।
gniourf_gniourf

তদ্ব্যতীত, লুপটি তাদের কাছে পৌঁছানোর আগে প্রক্রিয়া চলাকালীন মুছে ফেলা ফাইলগুলিও এটি পরীক্ষা করে।
লক্স্যাক্সস

1
আপনার ডিরেক্টরিdir.txt
vidstige

75
for file in Data/*.txt
do
    for ((i = 0; i < 3; i++))
    do
        name=${file##*/}
        base=${name%.txt}
        ./MyProgram.exe "$file" Logs/"${base}_Log$i.txt"
    done
done

name=${file##*/}প্রতিকল্পন ( শেল প্যারামিটার সম্প্রসারণ ) গত নেতৃস্থানীয় পথনাম আপ সরিয়ে ফেলা হবে/

দ্য base=${name%.txt}প্রতিকল্পন চিহ্ন সরিয়ে ফেলা হবে .txt। এক্সটেনশনগুলি পরিবর্তিত হতে পারে তবে এটি কিছুটা কৌশলযুক্ত।


3
আমি বিশ্বাস করি আপনার কোডটিতে একটি ত্রুটি আছে। এক লাইনের base=${name%.txt}পরিবর্তে হওয়া উচিত base=${base%.txt}
কেসক্লিম

4
@ ক্যাসি ক্লিমকোভস্কি: হ্যাঁ; কোড এবং মন্তব্যগুলি একমত না হলে তাদের মধ্যে কমপক্ষে একটি ভুল one এই ক্ষেত্রে, আমি মনে করি এটি কেবল একটি - কোড; প্রায়শই এটি উভয়ই ভুল are যে ইশারা জন্য ধন্যবাদ; আমি এটা ঠিক করেছি।
জোনাথন লেফলার

8

আপনি নিরাপদে ডিরেক্টরি স্ট্রাকচারের পুনরাবৃত্তি করতে নাল দ্বারা পৃথক আউটপুট বিকল্পটি ব্যবহার করতে পারেন।

#!/bin/bash
find . -type f -print0 | while IFS= read -r -d $'\0' file; 
  do echo "$file" ;
done

সুতরাং আপনার ক্ষেত্রে

#!/bin/bash
find . -maxdepth 1 -type f  -print0 | while IFS= read -r -d $'\0' file; do
  for ((i=0; i<=3; i++)); do
    ./MyProgram.exe "$file" 'Logs/'"`basename "$file"`""$i"'.txt'
  done
done

অতিরিক্ত

#!/bin/bash
while IFS= read -r -d $'\0' file; do
  for ((i=0; i<=3; i++)); do
    ./MyProgram.exe "$file" 'Logs/'"`basename "$file"`""$i"'.txt'
  done
done < <(find . -maxdepth 1 -type f  -print0)

স্ক্রিপ্ট (প্রক্রিয়া) এর বর্তমান স্কোপটিতে যখন লুপটি চালাবে এবং প্রয়োজনের প্রয়োজনে ভেরিয়েবল নির্ধারণে ফলাফলের আউটপুট ব্যবহারের অনুমতি দেয়


2
$'\0'লেখার একটি অদ্ভুত উপায় ''। তোমাকে মিস করছি IFS=এবং -rসুইচ read: আপনার পঠিত বিবৃতি হওয়া উচিত: IFS= read -rd '' file
gniourf_gniourf

আমি অনুমান করি যে কিছুগুলির জন্য অনুসন্ধানের প্রয়োজন হবে $'\0'এবং কিছু স্ট্যাক পয়েন্ট চারদিকে ছড়িয়ে দিন। সম্পাদনাগুলি করতে গিয়ে আপনি নির্দেশ করেছেন। IFS=চেষ্টা না করে এর খারাপ প্রভাবগুলি কী echo -e "ok \nok\0" | while read -d '' line; do echo -e "$line"; doneবলে মনে হচ্ছে এটি কোনওরকম নেই। এছাড়াও -আর আমি দেখি প্রায়শই ডিফল্ট থাকে তবে যা ঘটতে বাধা দেয় তার উদাহরণ খুঁজে পেল না।
জেমস

4
IFS=কোনও ফাইলের নাম কোনও স্থানের সাথে শেষ হওয়ার ক্ষেত্রে প্রয়োজন: touch 'Prospero 'চেষ্টাটি সাথে রয়েছে (পিছনের স্থানটি নোট করুন)। এছাড়াও আপনি প্রয়োজন -rসুইচ ক্ষেত্রে একটি ফাইলের নাম একটি ব্যাকস্ল্যাশ আছে: সঙ্গে এটি চেষ্টা touch 'Prospero\n'
gniourf_gniourf

-1

দেখে মনে হচ্ছে আপনি উইন্ডোজ ফাইল (.exe) চালানোর চেষ্টা করছেন অবশ্যই আপনার পাওয়ারশেল ব্যবহার করা উচিত। যাইহোক লিনাক্স ব্যাশ শেলের উপর একটি সাধারণ ওয়ান-লাইনার যথেষ্ট হবে।

[/home/$] for filename in /Data/*.txt; do for i in {0..3}; do ./MyProgam.exe  Data/filenameLogs/$filename_log$i.txt; done done

বা ব্যাশে

#!/bin/bash

for filename in /Data/*.txt; 
   do
     for i in {0..3}; 
       do ./MyProgam.exe Data/filename.txt Logs/$filename_log$i.txt; 
     done 
 done
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.