কোনও ফাইলের নাম শেল গ্লোব প্যাটার্নের সাথে মেলে কিনা তা আমি প্রোগ্রামগতভাবে কীভাবে বলতে পারি?


13

আমি বলতে চাই যে $stringএকটি গ্লোব প্যাটার্নের সাথে কোনও স্ট্রিং মিলছে কিনা $pattern$stringবিদ্যমান ফাইলের নাম বা নাও থাকতে পারে। কিভাবে আমি এটি করতে পারব?

আমার ইনপুট স্ট্রিংগুলির জন্য নিম্নলিখিত ফর্ম্যাটগুলি ধরে নিন:

string="/foo/bar"
pattern1="/foo/*"
pattern2="/foo/{bar,baz}"

আমি একটি ব্যাশ বাগ্ধারা নির্ধারণ করে যে যদি এটি চাই $stringদ্বারা মেলানো হবে $pattern1, $pattern2, বা অন্য কোন অবাধ উল্লিখিত glob প্যাটার্ন। আমি এখন পর্যন্ত যা চেষ্টা করেছি তা এখানে:

  1. [[ "$string" = $pattern ]]

    এটি প্রায় কাজ করে, ব্যতীত $patternস্ট্রিং প্যাটার্ন হিসাবে ব্যাখ্যা করা হয় এবং গ্লোব প্যাটার্ন হিসাবে নয়।

  2. [ "$string" = $pattern ]

    এই পদ্ধতির সাথে সমস্যাটি $patternহ'ল প্রসারিত হয় এবং তারপরে $stringএবং এর প্রসারণের মধ্যে স্ট্রিং তুলনা করা হয় $pattern

  3. [[ "$(find $pattern -print0 -maxdepth 0 2>/dev/null)" =~ "$string" ]]

    এটি কাজ করে, তবে কেবলমাত্র যদি $stringএমন কোনও ফাইল থাকে যা বিদ্যমান থাকে।

  4. [[ $string =~ $pattern ]]

    এটি কাজ করে না কারণ =~অপারেটর $patternএকটি গ্লোব বা ওয়াইল্ডকার্ড প্যাটার্ন নয়, বর্ধিত নিয়মিত অভিব্যক্তি হিসাবে ব্যাখ্যা করার কারণ ঘটায় ।


2
আপনি যে সমস্যাটি চালাতে যাচ্ছেন তা হ'ল এটি {bar,baz}কোনও নিদর্শন নয়। এটি প্যারামিটার সম্প্রসারণ। এর মধ্যে সূক্ষ্ম তবে সমালোচনামূলক পার্থক্যটি {bar,baz}খুব তাড়াতাড়ি একাধিক যুক্তিতে প্রসারিত হয় barএবং baz
প্যাট্রিক

শেলটি যদি প্যারামিটারগুলি প্রসারিত করতে পারে, তবে অবশ্যই স্ট্রিং কোনও গ্লোবের সম্ভাব্য প্রসারণ কিনা তা তা বলতে পারে।
jayhendren

এটিকে একবার ব্যবহার করে দেখুন = ls /foo/* এখন আপনি একটি
হ্যাকাহলিক

1
@ পেট্রিক: বাশ ম্যান পৃষ্ঠাটি পড়ার পরে আমি জানতে পেরেছি যে foo/{bar,baz}আসলে একটি ব্রেস এক্সপেনশন (প্যারামিটার এক্সপেনশন নয়) যখন পথের foo/*নাম সম্প্রসারণ। $stringপ্যারামিটার সম্প্রসারণ। এগুলি বিভিন্ন সময়ে এবং বিভিন্ন প্রক্রিয়া দ্বারা সম্পন্ন হয়।
jayhendren

@ জেহেেনড্রেন @ পেট্রিক ঠিক বলেছেন, এবং তারপরে আপনি শিখলেন যে আপনার প্রশ্নটি শেষ পর্যন্ত শিরোনামকে বিশ্বাস করতে পরিচালিত করে না। বরং আপনি বিভিন্ন ধরণের প্যাটার্নের সাথে স্ট্রিং মেলাতে চান। যদি আপনি কোনও গ্লোব প্যাটার্নের সাথে বনাম কঠোরভাবে মেলে থাকতে চান, তবে caseবিবৃতিটি ব্যাশ ম্যানুয়াল অনুসারে পাথনাম এক্সপেনশন ("গ্লোব্বিং") সম্পাদন করে।
মাইক এস

উত্তর:


8

এই সমস্যার কোনও সাধারণ সমাধান নেই। কারণটি হ'ল ব্যাশে, ব্রেস সম্প্রসারণ (যেমন, {pattern1,pattern2,...}এবং ফাইলের নাম সম্প্রসারণ (ওরফে গ্লোব ধরণ)) আলাদা জিনিস হিসাবে বিবেচিত হয় এবং বিভিন্ন পরিস্থিতিতে এবং বিভিন্ন সময়ে প্রসারিত হয় b

  • ধনুর্বন্ধনী প্রসার
  • তিলদে সম্প্রসারণ
  • প্যারামিটার এবং পরিবর্তনশীল প্রসারণ
  • কমান্ড প্রতিস্থাপন
  • পাটিগণিতের সম্প্রসারণ
  • শব্দ বিভাজন
  • পথের বিস্তৃতি

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

#!/bin/bash
set -f

string=/foo/bar

for pattern in /foo/{*,foo*,bar*,**,**/*}; do
    [[ $string == $pattern ]] && echo "$pattern matches $string"
done

এই স্ক্রিপ্টটি চালানো নিম্নলিখিত আউটপুট উত্পন্ন করে:

/foo/* matches /foo/bar
/foo/bar* matches /foo/bar
/foo/** matches /foo/bar

এটি কাজ করে কারণ set -fপথের নাম সম্প্রসারণ অক্ষম করে, সুতরাং কেবল ব্রেস প্রসারণ এবং টিলডে সম্প্রসারণ বিবৃতিতে ঘটে for pattern in /foo/{*,foo*,bar*,**,**/*}। এরপরে [[ $string == $pattern ]]ব্রেস প্রসারণের কাজ ইতিমধ্যে সম্পাদনের পরে আমরা প্যাথনাম বিস্তারের বিরুদ্ধে পরীক্ষার জন্য পরীক্ষা অপারেশনটি ব্যবহার করতে পারি ।


7

আমি বিশ্বাস করি না যে {bar,baz} এটি শেল গ্লোব প্যাটার্ন (যদিও অবশ্যই /foo/ba[rz]এটি) তবে আপনি যদি জানতে চান যে $stringম্যাচগুলি $patternকরতে পারেন তবে:

case "$string" in 
($pattern) put your successful execution statement here;;
(*)        this is where your failure case should be   ;;
esac

আপনি নিজের পছন্দ মতো অনেকগুলি করতে পারেন:

case "$string" in
($pattern1) do something;;
($pattern2) do differently;;
(*)         still no match;;
esac

1
হাই @ মিমক্জার্ভ, মন্তব্য এবং আমি উপরে যে উত্তর প্রদান করেছি তাতে ইঙ্গিত করা হয়েছে, আমি ইতিমধ্যে শিখেছি যে আপনি যা বলছেন সত্য - {bar,baz}এটি কোনও গ্লোব প্যাটার্ন নয়। আমি ইতিমধ্যে আমার প্রশ্নের সমাধান নিয়ে এসেছি যা এটি বিবেচনায় নেয়।
jayhendren

3
+1 এটি শিরোনাম এবং প্রথম বাক্যে প্রদত্ত ঠিক মত প্রশ্নের উত্তর দেয়। যদিও প্রশ্নটি পরে শেল গ্লোব নিদর্শনগুলির সাথে অন্যান্য নিদর্শনগুলিকে সংযুক্ত করে।
মাইকে এস

3

যেমন প্যাট্রিক নির্দেশ করেছেন আপনার প্যাটার্নের একটি "ভিন্ন ধরণের" প্রয়োজন:

[[ /foo/bar == /foo/@(bar|baz) ]]


string="/foo/bar"
pattern="/foo/@(bar|baz)"
[[ $string == $pattern ]]

উদ্ধৃতিগুলি সেখানে প্রয়োজনীয় নয়।


ঠিক আছে, এটি কাজ করে, তবে কঠোরভাবে বলতে গেলে, এটি আমার প্রশ্নের উত্তর দেয় না। উদাহরণস্বরূপ, আমি অন্য উত্স থেকে আগত নিদর্শনগুলি বিবেচনা করতে চাই, অর্থাৎ নিদর্শনগুলি আমার নিয়ন্ত্রণের বাইরে।
jayhendren

@jayhendren তারপরে আপনাকে সম্ভবত প্রথমে আগত প্যাটার্নগুলিকে সেই বাশ গ্রহণ হিসাবে রূপান্তর করতে হবে।
Hauke ​​Lage

সুতরাং আপনি যা করেছেন তা সবই আমার প্রশ্ন থেকে "কীভাবে বলব যদি ফাইলনামটি এক্সপ্রেশনটির সম্ভাব্য বর্ধন হয়" থেকে "আমি কীভাবে বাশ-স্টাইলের বর্ধিত গ্লোব নিদর্শনগুলিতে সাধারণ বাশ-শৈলীর ফাইলনামের ধরণগুলিকে রূপান্তর করব।"
jayhendren

@ জেহেনড্রেন বিবেচনা করে যে আপনি যা চান তা অসম্ভব বলে মনে হচ্ছে "আপনি যা কিছু করেছেন সত্যই" আমার কাছে কিছুটা অদ্ভুত মনে হলেও এটি কেবল একটি বিদেশী ভাষার জিনিস। আপনি যদি এই নতুন প্রশ্নটি জিজ্ঞাসা করতে চান তবে আপনাকে অবশ্যই ইনপুট প্যাটার্নগুলি কেমন তা ব্যাখ্যা করতে হবে। সম্ভবত এটি একটি সাধারণ sedঅপারেশন
Hauke ​​Lage

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

1

আমি গ্রিপ এভাবে ব্যবহার করব:

#!/bin/bash
string="/foo/bar"
pattern1="/foo/*"
pattern2="/foo/{bar,baz}"

if echo $string | grep -e "$pattern1" > /dev/null; then
    echo $string matches $pattern1
fi

if echo $string | grep -e "$pattern2" > /dev/null; then
    echo $string matches $pattern2
fi

যা আউটপুট দেয়:

./test2.bsh 
/foo/bar matches /foo/*

-2

জেডএসে:

[[ $string = $~pattern ]] && print true

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