BASH স্ক্রিপ্ট তৈরি করা space ফাঁকা জায়গাগুলি (বা workaround) সহ ফাইলের নাম হ্যান্ডেল করা


12

আমি বেশ কয়েক বছর ধরে BASH ব্যবহার করছি, যদিও BASH স্ক্রিপ্টিংয়ের সাথে আমার অভিজ্ঞতা তুলনামূলকভাবে সীমাবদ্ধ।

আমার কোডটি নীচের মতো। এটি বর্তমান ডিরেক্টরি ভিতরে পুরো ডিরেক্টরি কাঠামো দখল এবং এটিকে প্রতিলিপি করা উচিত $OUTDIR

for DIR in `find . -type d -printf "\"%P\"\040"`
do
  echo mkdir -p \"${OUTPATH}${DIR}\"        # Using echo for debug; working script will simply execute mkdir
  echo Created $DIR
done

সমস্যাটি হচ্ছে, এখানে আমার ফাইল কাঠামোর একটি নমুনা রয়েছে:

$ ls
Expect The Impossible-Stellar Kart
Five Iron Frenzy - Cheeses...
Five Score and Seven Years Ago-Relient K
Hello-After Edmund
I Will Go-Starfield
Learning to Breathe-Switchfoot
MMHMM-Relient K

স্পেসগুলি নোট করুন: -S এবং forশব্দ অনুসারে প্রতিটি পরামিতি নেয়, তাই আমার স্ক্রিপ্টের আউটপুটটি এরকম কিছু দেখাচ্ছে:

Creating directory structure...
mkdir -p "/myfiles/multimedia/samjmusicmp3test/Learning"
Created Learning
mkdir -p "/myfiles/multimedia/samjmusicmp3test/to"
Created to
mkdir -p "/myfiles/multimedia/samjmusicmp3test/Breathe-Switchfoot"
Created Breathe-Switchfoot

তবে এর আউটপুট থেকে পুরো ফাইলের নাম (একবারে একটি লাইন) দখল করা আমার দরকার find। আমি findপ্রতিটি ফাইলের নামের চারপাশে ডাবল-কোট তৈরি করার চেষ্টা করেছি। তবে এটি কোনও উপকারে আসে না।

for DIR in `find . -type d -printf "\"%P\"\040"`

এবং এই পরিবর্তিত রেখার সাথে আউটপুট:

Creating directory structure...
mkdir -p "/myfiles/multimedia/samjmusicmp3test/"""
Created ""
mkdir -p "/myfiles/multimedia/samjmusicmp3test/"Learning"
Created "Learning
mkdir -p "/myfiles/multimedia/samjmusicmp3test/to"
Created to
mkdir -p "/myfiles/multimedia/samjmusicmp3test/Breathe-Switchfoot""
Created Breathe-Switchfoot"

এখন, আমার এমন কিছু উপায়ের প্রয়োজন যা আমি এর মাধ্যমে পুনরাবৃত্তি করতে পারি, কারণ আমি gstreamerনিম্নলিখিত ফাইলের সাথে অনুরূপ আরও কাঠামোযুক্ত আরও জটিল কমান্ড চালাতে চাই । আমার এটি কীভাবে করা উচিত?

সম্পাদনা: আমার একটি কোড কাঠামো প্রয়োজন যা আমাকে প্রতিটি ডিরেক্টরি / ফাইল / লুপের জন্য একাধিক লাইন কোড চালানোর অনুমতি দেয়। আমি অস্পষ্ট থাকলে দুঃখিত।

সমাধান: আমি প্রথমে চেষ্টা করেছি:

find . -type d | while read DIR
do
  mkdir -p "${OUTPATH}${DIR}"
  echo Created $DIR
done

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

while read DIR
do
  mkdir -p "${OUTPATH}${DIR}"
  echo Created $DIR
done < <(find . -type d)

এটি পরে আমাকে লুপের মধ্যে শর্তসাপেক্ষে ইনক্রিমেন্ট ভেরিয়েবলগুলি অনুমতি দেয় যা স্ক্রিপ্টে পরে উপলব্ধ থাকবে।


Why_would_you_ever_need_a_space_in_a_file_name?
কেভিন প্যাঙ্কো

সত্য, আমার পছন্দ নয়। যদিও, স্পেসগুলি সরাতে আপনার প্রথমে স্পেসগুলির সাথে ফাইলগুলি পরিচালনা করতে হবে;)
স্যামুয়েল জেস্কে

1
প্রকৃতপক্ষে, ফাইলের নাম ফাঁকা করার অনুমতি দেওয়া উচিত। আমি /আর অচিরাচরিত অক্ষর ছাড়া অন্য কিছুকে অনুমতি দেব । তবে কিছু ব্যতীত অনুমোদিত /এবং \0তাই আপনাকে অবশ্যই এটিকে অনুমতি দেওয়া উচিত।
কেভিন প্যাঙ্কো

উত্তর:


11

আপনি findএকটি whileলুপ মধ্যে পাইপ করা প্রয়োজন ।

find ... | while read -r dir
do
    something with "$dir"
done

এছাড়াও, আপনাকে -printfএই ক্ষেত্রে ব্যবহার করতে হবে না ।

নলবাইট ডিলিমিটার ব্যবহার করে আপনি যদি চান তবে ফাইলগুলির বিরুদ্ধে এই প্রমাণগুলি তাদের নামে নতুন করে তুলতে পারেন (এটিই কেবলমাত্র একটি চরিত্র যা * নিক্স ফাইলপথে উপস্থিত হতে পারে না):

find ... -print0 | while read -d '' -r dir
do
    something with "$dir"
done

আপনি $()আরও বহুমুখী এবং সহজ হতে ব্যাকটিকগুলির পরিবর্তে ব্যবহার করতে পারবেন। এগুলি খুব সহজেই বাসা বাঁধতে পারে এবং উদ্ধৃতি আরও সহজেই করা যায়। এই স্বীকৃত উদাহরণটি এই বিষয়গুলি তুলে ধরে:

echo "$(echo "$(echo "hello")")"

ব্যাকটিক্স দিয়ে এটি করার চেষ্টা করুন।


2
এছাড়াও এর পরিবর্তে "$dir"এটি ব্যবহার করা পছন্দনীয় "${dir}"- $ {dir} নাম এবং $ ir dirname between এর মধ্যে পার্থক্যটি বলা সহজ, তবে $ dirname কোনওভাবেই ব্যাখ্যা করা যায়।
জেমস পোলি

এখানে গুরুত্বপূর্ণ বিষয়টি হ'ল readএকটি সম্পূর্ণ লাইনটি পড়ে ${dir}, তাই আইএফএসের কোনও বিষয় নেই।
জেমস পোলি 0

1
$ / "টাইপোটি খুঁজে বের করার জন্য ধন্যবাদ। ভেরিয়েবলের নাম অনুসরণ না করে যদি ধনুর্বন্ধনী প্রয়োজন হয় না
পরবর্তী বিজ্ঞপ্তি না দেওয়া পর্যন্ত

4
এটি স্পেস (U + 0020) সহ পাথের নামগুলি পরিচালনা করবে তবে লাইন ফিডস (U + 000A) সহ সঠিকভাবে প্যাথনামগুলি পরিচালনা করতে এটি ব্যর্থ হবে। আমি পছন্দ করি find … -print0 | xargs -0 …কারণ এটি যে ডিলিমিটারটি ব্যবহার করে তা হ'ল একমাত্র চরিত্রের সাথে হুবহু মিলে যায় যা POSIX পাঠ্যনামগুলিতে অনুমোদিত নয়: NUL (U +0000)।
ক্রিস জনসেন

2
পারফেক্ট! শুধু আমি যা খুঁজছিলাম। আপনি কখনও পাইপ করতে সক্ষম হবেন তা আমার কাছে কখনও ঘটেনি while। @ ক্রিস জনসেন: সত্য, তবে এমনকি সংগীত রিপিং প্রোগ্রামগুলি তাদের ফাইলের নামগুলিতে লাইনফিড রাখার ঝোঁকও রাখে না। এবং যদি তারা তা করে, আমি জানতে চাই (অর্থাত: কিছু ভুল হয়ে গেছে) এবং তত্ক্ষণাত সেগুলি থেকে মুক্তি দিতে পারি ...
স্যামুয়েল জয়েস্কে

8

এই উত্তরটি দেখুন আমি কিছু দিন আগে একটি স্ক্রিপ্টের উদাহরণের জন্য লিখেছিলাম যা ফাঁক দিয়ে ফাইলের নামগুলি পরিচালনা করে।

আপনি যা করার চেষ্টা করছেন তা অর্জন করার জন্য আরও কিছুটা বিশৃঙ্খলাযুক্ত (তবে আরও সংক্ষিপ্ত) উপায় রয়েছে:

find . -type d -print0 | xargs -0 -I {} mkdir -p ../theredir/{}

-print0একটি নাল দিয়ে যুক্তিগুলি পৃথক করার জন্য অনুসন্ধানকে বলে; -0 থেকে xargs এটিকে নাল দ্বারা পৃথক করা যুক্তিগুলি আশা করতে বলে। এর অর্থ এটি ফাঁকা জায়গাটিকে পরিচালনা করে।

-I {}xargs কে {}ফাইলের সাথে স্ট্রিং প্রতিস্থাপন করতে বলে । এটি এও বোঝায় যে কমান্ডলাইন অনুযায়ী কেবলমাত্র একটি ফাইলের নাম ব্যবহার করা উচিত (xargs সাধারণত লাইনে যতগুলি ফিট করবে)

বাকিগুলি সুস্পষ্ট হওয়া উচিত।


ডেনিস উইলিয়ামসনের পরামর্শটি অবশ্য (টাইপোগুলি বাদে) আরও বেশি পাঠযোগ্য এবং এভাবে প্রায় প্রতিটি উপায়েই পছন্দনীয়।
জেমস পোলি

এমকিডিরের জন্য কাজ করে, তবে দুঃখিত আমি আরও স্পষ্ট হওয়া উচিত ছিল - প্রতিটি ফাইলের জন্য আমি একাধিক কমান্ড চালাতে চাই। আপনি দেখতে পাচ্ছেন, আমার অনুরূপ রুটিনের জন্য পরে আমি ইনপুট ফাইলনামের উপর ভিত্তি করে একটি আউটপুট ফাইলের নাম উত্পন্ন করতে চাই (যার মধ্যে .ogg এক্সটেনশানটি কেড়ে নেওয়া এবং .mp3 যোগ করা জড়িত) এবং তারপরে জিএসটি-লঞ্চের আবেদন করার সময় আমার পাইপলাইনে এই একাধিক ভেরিয়েবলগুলি ব্যবহার করুন।
স্যামুয়েল জায়েস্কে

5

আপনি যে সমস্যার মুখোমুখি হচ্ছেন তা হ'ল বিবৃতিটি পৃথক যুক্তি হিসাবে সন্ধানের প্রতিক্রিয়া জানাচ্ছে। স্পেস ডিলিমিটার স্পেসে বিভক্ত না হওয়ার জন্য আপনাকে বাশের আইএফএস ভেরিয়েবল ব্যবহার করতে হবে।

এখানে কীভাবে এটি করা যায় তার একটি লিঙ্ক এখানে দেওয়া হয়েছে ।

আইএফএসের অভ্যন্তরীণ পরিবর্তনশীল

এই সমস্যাটির চারপাশের একটি উপায় হ'ল বাশের অভ্যন্তরীণ আইএফএস (অভ্যন্তরীণ ক্ষেত্র বিভাজক) পরিবর্তনশীল যাতে এটি ডিফল্ট হোয়াইটস্পেস (স্পেস, ট্যাব, নিউলাইন) ব্যতীত অন্য কোনও কিছু দ্বারা ক্ষেত্রগুলি বিভক্ত করে a

#!/bin/bash
IFS=$';'

for I in `find -type d -printf \"%P\"\;`
do
   echo "== $I =="
done

আপনার ক্ষেত্রের ডিলিমিটারকে% P এর পরে আউটপুট দেওয়ার জন্য আপনার অনুসন্ধানটি সেট করুন এবং আপনার আইএফএস যথাযথভাবে সেট করুন। আমি আধা-কোলন বেছে নিয়েছি কারণ এটি আপনার ফাইলের নামগুলিতে খুঁজে পাওয়ার সম্ভাবনা খুব বেশি।

অন্য বিকল্পটি হ'ল এমকেডিরকে সরাসরি অনুসন্ধান থেকে কল করে -execআপনি লুপের জন্য পুরোপুরি এড়াতে পারবেন না। এটি যদি আপনার অতিরিক্ত কোনও পার্সিংয়ের প্রয়োজন হয় না।


যদি ফাইলের নামটিতে আইএফএস থাকে? তারপরে আপনাকে অন্য একটি বেছে নিতে হবে। তবে তারপরে কী হবে ...
পরবর্তী বিজ্ঞপ্তি না হওয়া পর্যন্ত বিরতি দেওয়া হয়েছে।

3
আপনি /পসিক্স এবং :ডস ফাইল সিস্টেমগুলিতে বেছে নিতে পারেন । বিভিন্ন ফাইল সিস্টেমের জন্য অবৈধ অক্ষর রয়েছে যা আপনি আইএফএসের জন্য বেছে নিতে পারেন। আরও জটিল কিছু এবং আপনি পার্ল ব্যবহার করা ভাল।
ড্যারেন হল

2
/ ব্যবহার করে সমস্যা হ'ল এটি ডিরেক্টরি ডিলিমিটার এবং findস্ল্যাশ সহ পাথ সহ ফাইলের নামগুলি ফেরত দেয়। আপনার স্ক্রিপ্টের সেমিকোলনকে একটি স্ল্যাশে পরিবর্তন করার চেষ্টা করুন এবং প্রতিধ্বনিটি পৃথক লাইনে ডিরেক্টরি এবং ফাইলের নাম মুদ্রণ করবে।
পরবর্তী বিজ্ঞপ্তি না দেওয়া পর্যন্ত বিরতি দেওয়া হয়েছে।

এটিও বেশ দরকারী বলে মনে হচ্ছে। আমি পাইপে whileবিকল্পে চলেছি , তবে এটি বেশ কার্যকরও দেখায়। হ্যাঁ, আমার অনুরূপ কাঠামোর পরে আমার আরও বিশ্লেষণ করা দরকার। (ইনপুট ফাইলের নাম .ogg হবে, যা filesrcজিএসটি পাইপলাইন হিসাবে পাস হবে তবে আউটপুট ডিরেক্টরি ভিত্তিক। এমপি 3 এর সমাপ্তি উত্পন্ন হবে এবং পাইপলাইনেও পাস হবে filesink, অবশ্যই এটি করা দরকার প্রতিটি ফাইলের জন্য, কিছু echoব্যবহারকারীর
সাথেও

4

যদি আপনার লুপের বডি একক কমান্ডের চেয়ে বেশি হয় তবে শেল স্ক্রিপ্টটি চালানোর জন্য xargs ব্যবহার করা সম্ভব :

export OUTPATH=/some/where/else/
find . -type d -print0 | xargs -0 bash -c 'for DIR in "$@"; do
  printf "mkdir -p %q\\n" "${OUTPATH}${DIR}"        # Using echo for debug; working script will simply execute mkdir
  echo Created $DIR
done' -

শেলটি বোর্ন / পসিক্স বিভিন্নের (শেল স্ক্রিপ্টে $ 0 সেট করার জন্য ব্যবহৃত হয়) অন্তর্ভুক্ত থাকলে নিশ্চিত করুন এছাড়াও, উদ্ধৃতি দিয়ে যত্ন নিতে হবে, যেহেতু শেল স্ক্রিপ্ট সরাসরি প্রম্পটে পরিবর্তে উদ্ধৃত স্ট্রিংয়ের ভিতরে লেখা হচ্ছে।


আরেকটি আকর্ষণীয় ধারণা। ধন্যবাদ - আমি নিশ্চিত যে আমি এটির জন্য পরে একটি ব্যবহার খুঁজে
পাব

1

আপনার আপডেট প্রশ্নে

mkdir -p \"${OUTPATH}${DIR}\"

এই হওয়া উচিত

mkdir -p "${OUTPATH}${DIR}"

ধন্যবাদ। সংশোধন করা হয়েছে। এটি ডিআইআর - এর পরিবর্তে
ফাইল


0

বা পুরো জিনিসটিকে অনেক কম জটিল করে তুলতে:

% rsync -av --include='*/' --exclude='*' SRC DST

এটি এসআরসি-র ডিরেক্টরি কাঠামোটিকে ডিএসটি-তে প্রতিলিপি দেয়।


না, আমার মতো পুনরাবৃত্ত কাঠামো দরকার, যা আমাকে প্রতিটি ফাইলের জন্য একাধিক লাইন কোড চালানোর অনুমতি দেয়। "এখন, আমার এইরকম পুনরাবৃত্তি করতে পারে এমন কিছু উপায়ে আমার প্রয়োজন, কারণ আমি নিম্নলিখিত ফাইলের উপরের অনুরূপ কাঠামোতে gstreamer যুক্ত আরও জটিল কমান্ড চালাতে চাই" " আমি অস্পষ্ট থাকলে দুঃখিত।
স্যামুয়েল জায়েস্কে

আমি যে কমান্ডটি দিয়েছি তাতে যে সমস্যার জন্য আপনি জিজ্ঞাসা করেছিলেন সেগুলি সমাধান করে, এটি আপনার পক্ষে আরও বড় 'পাইপলাইনের' একটি অংশ কিনা তা বিবেচ্য নয়। প্রশ্নটিতে বর্ণিত হিসাবে অন্য কারও সমস্যা থাকলে আরএসসিএন-অ্যাপ্রোচ কাজ করবে। তাই হয়, কোন প্রয়োজন সম্ভাব্য unclearity সম্পর্কে :) দুঃখিত হতে
আকিরা

হ্যাঁ। না, আমার অর্থ আমি পরে অনুরূপ প্রসেসিং করতে একটি অনুরূপ while... do... doneকাঠামো ব্যবহার করব, যার জন্য প্রতিটি ফাইলের বিভিন্ন কোডের লাইনের প্রয়োজন (স্ট্রিং, ইকো, জিএসটি-লঞ্চ পরিবর্তন করুন) require ) এবং rsyncএটি অর্জন করবে না। এ কারণেই আমি নির্দিষ্ট করেছিলাম যে একই ধরণের স্ট্রুক্ট্রারের মধ্যে আরও জটিল কমান্ডের সেট চালানো আমার দরকার ছিল। আমার স্ক্রিপ্টটি এই লুপ কাঠামোটি দু'বার ব্যবহার করে, তাই প্রশ্নের জন্য আমি মাঝখানে কম ক্রুড সহ একটি পোস্ট করেছি।
স্যামুয়েল জ্যাশকে

0

আপনার যদি জিএনইউ সমান্তরাল http: // www.gnu.org/software/parallel/ ইনস্টল করা থাকে তবে আপনি এটি করতে পারেন:

find . -type d | parallel echo making {} ";" mkdir -p /tmp/outdir/{} ";" echo made {}

আরও জানতে জিএনইউ সমান্তরালের জন্য অন্তর্ভুক্ত ভিডিওটি দেখুন: http://www.youtube.com/watch?v=OpaiGYxkSuQ

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