ব্যাশে ডিরেক্টরি পাথ কীভাবে একটি রেইজেক্স পাস করবেন?


14

আমি একটি ডিরেক্টরি anacondaবা minicondaআমার ব্যবহারকারীর ডিরেক্টরি ডিরেক্টরি আছে কিনা তা খুঁজে পেতে একটি ছোট বাশ স্ক্রিপ্ট লিখেছি $HOME। তবে এটি miniconda2আমার বাড়িতে ডিরেক্টরিটি খুঁজে পায় না ।

আমি কীভাবে এটি ঠিক করতে পারি?

if [ -d "$HOME"/"(ana|mini)conda[0-9]?" ]; then
    echo "miniconda directory is found in your $HOME"
else
    echo "anaconda/miniconda is not found in your $HOME"
fi

পিএস: যদি আমার থাকে [ -d "$HOME"/miniconda2 ]; thenতবে এটি মিনিকোন্ডা 2 ডিরেক্টরিটি আবিষ্কার করে তাই আমি মনে করি যে অংশটি ত্রুটি রয়েছে"(ana|mini)conda[0-9]?"

আমি চাই স্ক্রিপ্টটি সাধারণ হোক। আমার জন্য এটি মিনিকোন্ডা 2 তবে অন্য কোনও ব্যবহারকারীর পক্ষে এটি অ্যানাকোন্ডা 2, মিনিকোন্ডা 3 ইত্যাদি হতে পারে।


অন্য ব্যবহারকারী অ্যানাকোন্ডা_2 বা -2 বা -2017 ব্যবহার করতে পারেন। তাহলে কি এক্সএক্সএক্সকোন্ডা * আরও ভাল হবে না?
WinEunuuchs2 ইউনিক্স

2
বাশ ফাইলের নাম সম্প্রসারণ গ্লোব এক্সপ্রেশন ব্যবহার করে, রেজিজেসগুলি নয়।
পিটার কর্ডেস

উত্তর:


13

এটি দুর্দান্তভাবে করা একটি আশ্চর্যজনক কৌশল y

মৌলিকভাবে, -dকেবলমাত্র একটি একক যুক্তি পরীক্ষা করা হবে - এমনকি আপনি যদি নিয়মিত প্রকাশের সাহায্যে ফাইলের সাথে মেলাতে পারেন।

একটি উপায় হ'ল সমস্যাটি প্রায়শই ফ্লিপ করা এবং ডিরেক্টরিগুলির জন্য রেজেক্স ম্যাচটি পরীক্ষা করার পরিবর্তে একটি রেগেক্স ম্যাচের জন্য ডিরেক্টরিগুলি পরীক্ষা করা। অন্য কথায়, একটি সাধারণ শেল গ্লোব ব্যবহার করে সমস্ত ডিরেক্টরি লুপ করে নিন $HOMEএবং আপনার রেজেক্সের বিরুদ্ধে প্রতিটি পরীক্ষা করে একটি ম্যাচ ভেঙে শেষ পর্যন্ত BASH_REMATCHঅ্যারেটি খালি নয় কিনা তা পরীক্ষা করে দেখুন :

#!/bin/bash

for d in "$HOME"/*/; do
  if [[ $d =~ (ana|mini)conda[0-9]? ]]; then
    break;
  fi
done

if ((${#BASH_REMATCH[@]} > 0)); then
    echo "anaconda/miniconda directory is found in your $HOME"
  else
    echo "anaconda/miniconda is not found in your $HOME"
fi

একটি বিকল্প উপায় হ'ল রেজেক্সের জায়গায় একটি বর্ধিত শেল গ্লোব ব্যবহার করা এবং কোনও অ্যারে-তে কোনও গ্লোব ম্যাচ ক্যাপচার করা। তারপরে অ্যারেটি খালি না থাকলে পরীক্ষা করুন:

#!/bin/bash

shopt -s extglob nullglob

dirs=( "$HOME"/@(ana|mini)conda?([0-9])/ )

if (( ${#dirs[@]} > 0 )); then
  echo "anaconda/miniconda directory is found in your $HOME"
else
  echo "anaconda/miniconda is not found in your $HOME"
fi

অনুচ্ছেদটি /নিশ্চিত করে যে কেবল ডিরেক্টরিগুলি মিলছে; nullglobশূন্য ম্যাচ ক্ষেত্রে অপ্রতিম স্ট্রিং ফিরে থেকে খোলসের বাধা দেয়।


হয় পুনরাবৃত্তি করতে globstarশেল বিকল্প ( shopt -s globstar) সেট করুন এবং যথাক্রমে: -

  • (রেজেক্স সংস্করণ): for d in "$HOME"/**/; do

  • (বর্ধিত গ্লোব সংস্করণ): dirs=( "$HOME"/**/@(ana|mini)conda?([0-9])/ )


1
আমি অ্যারে রুটে যাব। আপনি ?([0-9])এর জায়গায় ব্যবহার করতে পারেন @(|[0-9])- ?(...)শূন্য বা একের সাথে মিলে যায়, রেজেক্স কোয়ানটিফায়ারের সমান ?
গ্লেন জ্যাকম্যান

2
এমনকি আপনার এক্সট্লোব দরকার নেই আপনি ব্রেস প্রসারণ ব্যবহার করুন (এটি সমস্ত সম্ভাব্য মিলের নাম উত্পন্ন করে):~/{ana,mini}conda{0..9}*/
xenoid

সেখানে এটি রাখা হবে পারেন এই সমস্যার সমাধান সম্পাদনা তাই আসলে এমনকি যদি miniবা anacondaমধ্যে ইনস্টল করা হয় $HOME/sub-directories? উদাহরণস্বরূপ$HOME/sub-dir1/sub-dir2/miniconda2
জেনি

1
@ জেনি দয়া করে আমার সম্পাদনা দেখুনglobstar
স্টিল্ড্রাইভার

1
@ ইটারডন হ্যাঁ আমি "ডান" জিনিসটি কী মিলবে তার খরগোশের ছিদ্রটি নীচে নামতে চাইনি - আমি সাধারণ পদ্ধতির চিত্র তুলে ধরার উদ্দেশ্যে কেবল
ওপি'র রেজিক্সকেই

9

প্রকৃতপক্ষে, ইতিমধ্যে উল্লিখিত হিসাবে, এটি কৃপণ। আমার পদ্ধতির নিম্নলিখিত:

  • প্রশ্নযুক্ত ডিরেক্টরিগুলি সন্ধান করতে ব্যবহার করুন findএবং এর রেজেক্স ক্ষমতাগুলি।
  • প্রতিটি পাওয়া ডিরেক্টরি জন্য findএকটি মুদ্রণ যাকx
  • xএকটি স্ট্রিং এ এস সংরক্ষণ করুন
  • যদি স্ট্রিংটি খালি না থাকে, তবে ডিরেক্টরিগুলির একটি খুঁজে পাওয়া গেল।

এভাবে:

xString=$(find $HOME -maxdepth 1 \
                     -type d \
                     -regextype egrep \
                     -regex "$HOME/(ana|mini)conda[0-9]?" \
                     -printf 'x');
if [ -n "$xString" ]; then
    echo "found one of the directories";
else
    echo "no match.";
fi

ব্যাখ্যা:

  • find $HOME -maxdepth 1নীচের সমস্ত কিছু সন্ধান করে $HOME তবে অনুসন্ধানটি এক স্তরে সীমাবদ্ধ করে (এটি: এটি সাব-ডিরেক্টরিতে পুনরাবৃত্তি করে না)।
  • -type dশুধুমাত্র সার্চ সীমিত directories
  • -regextype egrepআমরা findকোন ধরণের নিয়মিত প্রকাশের সাথে কথা বলি তা জানায় । এটি প্রয়োজনীয় কারণ কারণগুলি জিনিসগুলি কিছুটা বিশেষ এবং পছন্দ হয় [0-9]?এবং (…|…)সেগুলি find ডিফল্টরূপে স্বীকৃতি দেয় না।
  • -regex "$HOME/(ana|mini)conda[0-9]?"আসল নিয়মিত প্রকাশ যা আমরা সন্ধান করতে চাই
  • -printf 'x' পূর্ববর্তী শর্তগুলি সন্তুষ্ট xকরে এমন প্রতিটি জিনিসের জন্য কেবল একটি মুদ্রণ করে ।

যখন ম্যাচ হয়। -bash: -regex: command not found found one of the directories
জেনি

হাই পার্লডাক: ধন্যবাদ একটি দুর্দান্ত উত্তর। তবে আমি একটি ত্রুটি printfপেয়েছি উদাহরণস্বরূপ আমি যখন স্ক্রিপ্টটি চালাচ্ছি, এটি ঠিক আছে তবে কোনও মিল নেই যখন এটি প্রিন্টফ কমান্ডের সন্ধান পায় না তবে আমি মনে করি এটি কারণ এটি প্রিন্ট করার মতো কিছু নেই ?. -bash: -printf: command not found no match.
জেনি

3
@ জেনি আপনি এটি অনুলিপি করার সময় একটি টাইপো বানিয়ে থাকতে পারেন, যেহেতু এটি আমার পক্ষে ভাল কাজ করে। -printfএকটি আদেশ নয় বরং একটি যুক্তি find। এটি আগের লাইনের শেষে ব্যাকস্ল্যাশ করে।
wjandrea

1
সন্ধানের -quitপথটি মুদ্রণের পরে আমি পরামর্শ দেব , যদি না আপনি অস্পষ্টতা সনাক্ত করতে চান
পিটার কর্ডেস

এবং কেন আসল পথ মুদ্রণ করবেন না? আপনার কাছে এটি ইতিমধ্যে রয়েছে, সুতরাং এটি ফেলে দেওয়া এবং xপরিবর্তে এটি ব্যবহার করা লজ্জার বলে মনে হচ্ছে :foundDir=$(find $HOME -maxdepth 1 -type d -regextype egrep -regex "$HOME/(ana|mini)conda[0-9]?" -print -quit); echo "found $foundDir"
টেরডন

2

আপনি যে ডিরেক্টরি ডিরেক্টরিটি পরীক্ষা করতে চান তার একটি তালিকা লুপ করতে পারেন এবং এর মধ্যে যদি কোনও উপস্থিত থাকে তবে এটিতে কাজ করতে পারেন:

a=0
for i in {ana,mini}conda{,2}; do
  if [ -d "$i" ]; then
    unset a
    break
  fi
done
echo "anaconda/miniconda directory is ${a+not }found in your $HOME"

এই সমাধানটি স্পষ্টতই পুরো রেজেক্স পাওয়ার জন্য অনুমতি দেয় না, তবে শেল গ্লোব্বিং এবং ব্রেস প্রসারণ কমপক্ষে আপনি যে ক্ষেত্রে দেখিয়েছেন তার ক্ষেত্রে সমান। একটি ডিরেক্টরি উপস্থিত হওয়ার সাথে সাথে লুপটি প্রস্থান করে এবং পূর্ববর্তী সেট ভেরিয়েবলটি আনসেট করে a। পরবর্তী echoলাইনে, প্যারামিটারের ${a+not } প্রসারণটি aসেট করা থাকলে (= কোনও দির পাওয়া যায়নি) এবং অন্য কিছু না হলে কিছুতেই প্রসারিত হয় ।


1

আশেপাশের সম্ভাব্য কাজগুলি নীচের চিত্রের মতো আলাদাভাবে মিনিকোন্ডা এবং অ্যানাকোন্ডা অনুসন্ধান করছে

if [ -d "$HOME"/miniconda* ] || [ -d "$HOME"/anaconda* ]; then
    echo "miniconda directory is found in your $HOME"
else
    echo "anaconda/miniconda is not found in your $HOME"
fi

তবে কারও কাছে যদি পরামর্শ থাকে তবে আমি জানতে চাই যে ডিরেক্টরিগুলি অনুসন্ধান করার সময় আমরা কেন একটি রেজেক্স পাস করতে পারি না।


2
আমি এটিকে উন্নত করে দিয়েছি - তবে বুঝতে পেরেছি যদি ব্যবহারকারীর একাধিক ম্যাচিং ডিরেক্টরি থাকে (যেমন: মিনিকোন্ডা এবং মিনিকোন্ডা 2)
স্টিল্ড্রাইভার

@ স্টিলড্রাইভার: "ব্যবহারকারীর একাধিক মেলানো ডিরেক্টরি থাকলে এটি ভেঙে যাবে" হ্যাঁ, সত্যই সত্য। কীভাবে এটি ঠিক করবেন আপনার কোনও পরামর্শ আছে?
জেনি

@ জেনি স্টেলিড্রাইভারের উত্তরের মতো একটি অ্যারে ব্যবহার করুন। shopt -s nullglob; dirs=( "$HOME"/miniconda* "$HOME"/anaconda* ); if (( ${#dirs[@]} > 0 )); then ...
wjandrea

যদি আপনি এটির ] || [সাথে প্রতিস্থাপন করেন -oতবে উভয় ডিরেক্টরি গ্লোব হিসাবে একই পরীক্ষায় সন্ধান করা হলে উভয় ডিরেক্টরি খুঁজে পাওয়া গেলে তা ভাঙা উচিত নয়।
ফিনিক্স

@ স্টিল্ড্রাইভার এবং জেনি: আপনি হয়ত এটি বেছে নেওয়ার পরিবর্তে অস্পষ্টতা ছিন্ন করতে চান । ব্যবহারকারীকে সম্ভবত তাদের ভুল ডিরেক্টরি বেছে নেওয়ার পরিবর্তে তাদের ডিরেক্টরি নির্দিষ্ট করুন। (যেমন স্বতঃ সনাক্তকরণ কোড চালানোর পরিবর্তে ডীর নামটি সেট করতে স্ক্রিপ্টটি সম্পাদনা করুন))
পিটার কর্ডেস
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.