আপনি যে সমাধানগুলি সংযুক্ত করছেন এটি বাস্তবে বেশ ভাল। কিছু উত্তরের ব্যাখ্যার অভাব থাকতে পারে, সুতরাং আসুন এটি বাছাই করুন, সম্ভবত আরও কিছু যুক্ত করুন।
আপনার এই লাইন
for file in *.txt
ইঙ্গিতটি আগে থেকেই জানা হয়ে গেছে (দ্রষ্টব্য: পসিক্স-অনুবর্তী পরিবেশগুলি সংবেদনশীল, *.txt
মিলবে না FOO.TXT
) case এ ক্ষেত্রে
basename -s .txt "$file"
এক্সটেনশন ছাড়াই নামটি ফিরিয়ে দেওয়া উচিত ( basename
ডিরেক্টরি পথটিও সরিয়ে দেয়: /directory/path/filename
→ filename
; আপনার ক্ষেত্রে এটি বিবেচ্য নয় কারণ এ $file
জাতীয় পাথ থাকে না)। আপনার কোডে টুল ব্যবহার করতে, আপনাকে কমান্ড প্রতিকল্পন যে সাধারণভাবে ভালো দেখায় প্রয়োজন: $(some_command)
। কমান্ড প্রতিস্থাপন আউটপুট নেয় some_command
, এটিকে একটি স্ট্রিং হিসাবে গণ্য করে এবং যেখানে সেখানে রাখে $(…)
। আপনার নির্দিষ্ট পুনর্নির্দেশটি হবে
… > "./$(basename -s .txt "$file")_sorted.txt"
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the output of basename will replace this
নেস্টেড উদ্ধৃতিগুলি এখানে ঠিক আছে কারণ বাশের ভিতরে $(…)
থাকা উক্তিগুলি একত্রে যুক্ত হয় তা জানতে যথেষ্ট স্মার্ট ।
এই উন্নতি করা যেতে পারে। নোটটি basename
পৃথক সম্পাদনযোগ্য, শেল বিল্টিন নয় (বাশ রানে type basename
, তুলনা করুন type cd
)। যে কোনও অতিরিক্ত প্রক্রিয়া তৈরি করা ব্যয়বহুল, এটি সংস্থান এবং সময় নেয়। এটি একটি লুপ মধ্যে স্প্যানিং সাধারণত খারাপ অভিনয় করে। অতএব অতিরিক্ত প্রক্রিয়া এড়াতে শেল আপনাকে যা দেবে তা ব্যবহার করা উচিত। এক্ষেত্রে সমাধানটি হ'ল:
… > "./${file%.txt}_sorted.txt"
আরও সাধারণ ক্ষেত্রে নিচের বাক্য গঠনটি নীচে ব্যাখ্যা করা হয়েছে।
আপনি যদি এক্সটেনশনটি জানেন না:
… > "./${file%.*}_sorted.${file##*.}"
বাক্য গঠনটি ব্যাখ্যা করেছে:
${file#*.}
- $file
, তবে সংক্ষিপ্ততম স্ট্রিং মিলটি *.
সামনে থেকে সরানো হয়েছে;
${file##*.}
- $file
, তবে দীর্ঘতম স্ট্রিং মিলটি *.
সামনে থেকে সরানো হবে; এটি কেবলমাত্র একটি এক্সটেনশন পেতে ব্যবহার করুন;
${file%.*}
- $file
, তবে সংক্ষিপ্ততম স্ট্রিংয়ের মিলটি .*
শেষ থেকে সরানো হবে; এক্সটেনশন ব্যতীত সমস্ত কিছু পেতে এটি ব্যবহার করুন;
${file%%.*}
- $file
, তবে দীর্ঘতম স্ট্রিংয়ের সাথে মিলটি .*
শেষ থেকে সরানো হবে;
প্যাটার্নের মিলটি গ্লোব-সদৃশ, রেজেক্স নয়। এর অর্থ *
হ'ল শূন্য বা আরও বেশি অক্ষরের ?
জন্য ওয়াইল্ডকার্ড , হ'ল একটি চরিত্রের জন্য ওয়াইল্ডকার্ড ( ?
যদিও আপনার ক্ষেত্রে আমাদের প্রয়োজন নেই )। আপনি যখন অনুরোধ করেন ls *.txt
বা for file in *.txt;
আপনি একই প্যাটার্নের মিলের প্রক্রিয়া ব্যবহার করেন। ওয়াইল্ডকার্ড ছাড়াই একটি প্যাটার্ন অনুমোদিত। আমরা ইতিমধ্যে ব্যবহার করেছেন ${file%.txt}
যেখানে .txt
প্যাটার্ন।
উদাহরণ:
$ file=name.name2.name3.ext
$ echo "${file#*.}"
name2.name3.ext
$ echo "${file##*.}"
ext
$ echo "${file%.*}"
name.name2.name3
$ echo "${file%%.*}"
name
তবে সাবধান:
$ file=extensionless
$ echo "${file#*.}"
extensionless
$ echo "${file##*.}"
extensionless
$ echo "${file%.*}"
extensionless
$ echo "${file%%.*}"
extensionless
এই কারণে নিম্নলিখিত বিপরীতে কার্যকর হতে পারে (তবে এটি নীচে ব্যাখ্যা নয়):
${file#${file%.*}}
এটি এক্সটেনশন ( ${file%.*}
) ব্যতীত সমস্ত কিছু সনাক্ত করে কাজ করে , তারপরে এটি পুরো স্ট্রিং থেকে সরিয়ে দেয়। ফলাফলগুলি এরকম:
$ file=name.name2.name3.ext
$ echo "${file#${file%.*}}"
.ext
$ file=extensionless
$ echo "${file#${file%.*}}"
$ # empty output above
নোটটি এবার .
অন্তর্ভুক্ত করা হয়েছে। $file
আক্ষরিক *
বা যদি আপনি অপ্রত্যাশিত ফলাফল পেতে পারেন ?
; তবে উইন্ডোজ (যেখানে এক্সটেনশনগুলি গুরুত্বপূর্ণ) ফাইলের নামগুলিতে এই অক্ষরগুলিকে যেভাবেই অনুমতি দেয় না, তাই আপনার পাত্তা নাও দিতে পারে। তবে […]
বা {…}
যদি উপস্থিত থাকে তবে তাদের নিজস্ব প্যাটার্ন মেলানো স্কিমটি ট্রিগার করতে পারে এবং সমাধানটি ভেঙে দিতে পারে!
আপনার "উন্নত" পুনঃনির্দেশটি হ'ল:
… > "./${file%.*}_sorted${file#${file%.*}}"
দুর্ভাগ্যক্রমে, এটি স্কোয়ার বা কোঁকড়া বন্ধনীর সাথে না হলেও প্রসার সহ বা ছাড়াই ফাইলের নামগুলি সমর্থন করা উচিত support বেশ লজ্জা। এটি ঠিক করার জন্য আপনাকে অভ্যন্তরীণ ভেরিয়েবলের দ্বিগুণ উদ্ধৃতি দিতে হবে।
সত্যিই উন্নত পুনঃনির্দেশ:
… > "./${file%.*}_sorted${file#"${file%.*}"}"
ডাবল উদ্ধৃতি ${file%.*}
একটি নিদর্শন হিসাবে কাজ করে না! অভ্যন্তরীণ এবং বাহ্যিক উদ্ধৃতিগুলি পৃথকভাবে বলার জন্য বাশ যথেষ্ট স্মার্ট কারণ অভ্যন্তরীণগুলি বহির্মুখী ${…}
বাক্য বিন্যাসে এম্বেড হয়েছে । আমি মনে করি এটি সঠিক উপায় ।
আরেকটি (অপূর্ণ) সমাধান, আসুন এটি শিক্ষামূলক কারণে বিশ্লেষণ করুন:
${file/./_sorted.}
এটি প্রথমটির .
সাথে প্রতিস্থাপন করে _sorted.
। আপনার সর্বাধিক একটি বিন্দু থাকলে এটি কাজ করবে $file
। একটি অনুরূপ সিনট্যাক্স রয়েছে ${file//./_sorted.}
যা সমস্ত বিন্দু প্রতিস্থাপন করে। আমি যতদূর জানি কেবলমাত্র শেষ বিন্দুটি প্রতিস্থাপনের কোনও বৈকল্পিক নেই ।
এখনও .
দৃ looks় দেখতে ফাইলগুলির প্রাথমিক সমাধান । Extensionless সমাধান $file
তুচ্ছ হল: ${file}_sorted
। এখন আমাদের দুটি কেসকে আলাদা করার একটি উপায় need এটা এখানে:
[[ "$file" == *?.* ]]
এটি প্রস্থান স্থিতি 0 (সত্য) প্রদান করে যদি কেবলমাত্র যদি $file
ভেরিয়েবলের বিষয়বস্তু ডান হাতের প্যাটার্নটির সাথে মেলে। প্যাটার্নটিতে বলা হয়েছে "কমপক্ষে একটি চরিত্রের পরে একটি বিন্দু আছে" বা সমতুল্য "এমন একটি বিন্দু রয়েছে যা শুরুতে নয়"। পয়েন্টটি হ'ল লিনাক্সের লুকানো ফাইলগুলি (উদাহরণস্বরূপ .bashrc
) এক্সটেনশনহীন হিসাবে বিবেচনা করা, যদি না কোথাও অন্য বিন্দু না থাকে।
নোট আমাদের [[
এখানে প্রয়োজন , না [
। প্রাক্তনটি আরও শক্তিশালী তবে দুর্ভাগ্যক্রমে বহনযোগ্য নয় ; পরেরটি পোর্টেবল তবে আমাদের জন্য সীমাবদ্ধ।
যুক্তি এখন এইভাবে:
[[ "$file" == *?.* ]] && file1="./${file%.*}_sorted.${file##*.}" || file1="${file}_sorted"
এর পরে, $file1
কাঙ্ক্ষিত নাম রয়েছে, তাই আপনার পুনঃনির্দেশটি হওয়া উচিত
… > "./$file1"
এবং পুরো কোড স্নিপেট ( আমরা কোনও এক্সটেনশন বা কোনও এক্সটেনশন দিয়ে কাজ করি তা নির্দেশ করে *.txt
প্রতিস্থাপন করা *
হয়েছে):
for file in *;
do
printf 'Processing %s\n' "$file"
[[ "$file" == *?.* ]] && file1="./${file%.*}_sorted.${file##*.}" || file1="${file}_sorted"
LC_ALL=C sort -u "$file" > "./$file1"
done
এটি ডিরেক্টরিগুলি (যদি থাকে) পাশাপাশি প্রক্রিয়া করার চেষ্টা করবে; আপনি ইতিমধ্যে জানেন কি করতে হবে তা এটা ঠিক করার।
… > "./${file%.txt}_sorted.txt"
"অতিরিক্ত প্রক্রিয়াগুলি এড়িয়ে চলে" - এটি কি কারণ আমরা এখানে লুপের$file
বাইরে চলকটিতে বেসনামটি ব্যবহার করছিfor
:basename -s .txt "$file"
... বা আমি ভুল বুঝেছি?