বাশে এক্সটেনশন ছাড়াই ফাইলের নাম পান


6

আমার ফোল্ডারের অভ্যন্তরে সমস্ত পাঠ্য ফাইল forপৃথকভাবে নীচের লুপ রয়েছে sort(অর্থাত্ প্রতিটিটির জন্য সাজানো আউটপুট ফাইল উত্পাদন করা)।

for file in *.txt; 
do
   printf 'Processing %s\n' "$file"
   LC_ALL=C sort -u "$file" > "./${file}_sorted"  
done

এটি প্রায় নিখুঁত, এটি বর্তমানে ফর্ম্যাটটিতে ফাইলগুলি আউটপুট দেয়:

originalfile.txt_sorted

... যদিও আমি এটির ফর্ম্যাটটিতে ফাইলগুলি আউটপুট করতে চাই:

originalfile_sorted.txt 

কারণ ${file}ভেরিয়েবলটিতে এক্সটেনশন সহ ফাইলের নাম রয়েছে। আমি উইন্ডোজ এর উপরে সাইগউইন চালাচ্ছি। সত্যিকারের লিনাক্স পরিবেশে এটি কীভাবে আচরণ করবে তা আমি নিশ্চিত নই, তবে উইন্ডোজে এক্সটেনশনের এই স্থানান্তরটি ফাইলটিকে উইন্ডোজ এক্সপ্লোরার দ্বারা অ্যাক্সেসযোগ্য করে তোলে।

আমি কীভাবে ফাইলের _sortedনামটি এক্সটেনশান থেকে আলাদা করতে পারি যাতে আমি উইন্ডোজের ফাইল এক্সটেনশনগুলি অক্ষত রাখার সাথে সাথে ফাইলগুলির মূল এবং সাজানো সংস্করণগুলিকে সহজেই আলাদা করতে পারি?

সম্ভাব্য সমাধানগুলি কী হতে পারে তা আমি খুঁজছিলাম তবে আমার কাছে এগুলি আরও জটিল সমস্যার সাথে মোকাবিলা করার জন্য আরও সজ্জিত বলে মনে হয়। আরও গুরুত্বপূর্ণভাবে, আমার বর্তমান জ্ঞানের সাথে তারা আমার মাথার উপর দিয়ে যায়, তাই আমি আশাবাদটি ধরে রেখেছি যে একটি সহজ সমাধান আছে যা আমার নম্র লুপের জন্য প্রযোজ্য , বা অন্য কেউ কীভাবে আমার পরিস্থিতিতে সেই সমাধানগুলি প্রয়োগ করতে পারে তা ব্যাখ্যা করতে পারে।bashfor

উত্তর:


19

আপনি যে সমাধানগুলি সংযুক্ত করছেন এটি বাস্তবে বেশ ভাল। কিছু উত্তরের ব্যাখ্যার অভাব থাকতে পারে, সুতরাং আসুন এটি বাছাই করুন, সম্ভবত আরও কিছু যুক্ত করুন।

আপনার এই লাইন

for file in *.txt

ইঙ্গিতটি আগে থেকেই জানা হয়ে গেছে (দ্রষ্টব্য: পসিক্স-অনুবর্তী পরিবেশগুলি সংবেদনশীল, *.txtমিলবে না FOO.TXT) case এ ক্ষেত্রে

basename -s .txt "$file"

এক্সটেনশন ছাড়াই নামটি ফিরিয়ে দেওয়া উচিত ( basenameডিরেক্টরি পথটিও সরিয়ে দেয়: /directory/path/filenamefilename; আপনার ক্ষেত্রে এটি বিবেচ্য নয় কারণ এ $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"... বা আমি ভুল বুঝেছি?
হাশিম

@ হাশিম … > "./${file%.txt}_sorted.txt"আপনার স্ক্রিপ্টে আপনাকে একমাত্র পরিবর্তন করতে হবে (উপবৃত্ত মাত্র আপনার সমস্ত কিছু নির্দেশ করে >, এটি আপনার স্ক্রিপ্টে রাখা উচিত এমন একটি প্রকৃত চরিত্র নয় ; প্রতিস্থাপন >এবং বাকী রেখার সাথে > "./${file%.txt}_sorted.txt")। এটি অতিরিক্ত প্রসেস কারণ এখন আমরা ব্যবহার করি না এড়াতে basename এ সব ; পুরো ম্যাজিকটি শেল নিজেই ${file%.txt}সিনট্যাক্সকে ধন্যবাদ দিয়ে সম্পন্ন করে । পার্শ্ব নোট: একমাত্র basename -s .txt "$file"কিছু ছাপায়; আপনি যদি ভাবেন যে এটি পরিবর্তনশীল পরিবর্তন করে, আপনি ভুল wrong
কামিল ম্যাকিয়েরোভস্কি

আহ, সুতরাং কমান্ড প্রতিস্থাপনের পরিবর্তে পরিবর্তে ব্যবহৃত হচ্ছে basename। আমি দেখি. আপনার সাহায্যের জন্য আবার ধন্যবাদ।
হাশিম

1
পছন্দ করেছেন এই খণ্ডটি > "./$(basename -s .txt "$file")_sorted.txt"কমান্ড প্রতিস্থাপন ব্যবহার করে, কমান্ডটি হয় basename …। আপনি হয় এটি ব্যবহার করেন বা > "./${file%.txt}_sorted.txt"যা কমান্ড প্রতিস্থাপন ব্যবহার করে না। সুতরাং এটি (কমান্ড সাবস্টিটিউশন + basename) xor${file%.txt} কমান্ড সাবস্টিটিউশন ছাড়াই অভিনব পরিবর্তনশীল প্রসারণ ।
কামিল ম্যাকিয়েরোভস্কি

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