ব্যাশের পথে নামের সাথে প্যাটার্ন মিলছে


10

আমি একটি ডিরেক্টরিতে সাব ডিরেক্টরি ডিরেক্টরিতে কাজ করতে চাই। বিবেচনা:

for x in x86-headers/*/C/populate.sh; do echo $x; done

এই দেয়

x86-headers/elf/C/populate.sh
x86-headers/gl/C/populate.sh
x86-headers/gmp/C/populate.sh
x86-headers/gnome2/C/populate.sh
x86-headers/gtk2/C/populate.sh
x86-headers/jni/C/populate.sh
x86-headers/libc/C/populate.sh

কিন্তু আমি মান পথের দ্বিতীয় অংশ অনুরূপ, চাই elf, glইত্যাদি আমি জানি বন্ধ স্ট্রিপ কিভাবে নেতৃস্থানীয় x86-headers

for x in x86-headers/*/C/populate.sh; do i=${x##x86-headers/}; echo $i; done

যা দেয়

elf/C/populate.sh
gl/C/populate.sh
gmp/C/populate.sh
gnome2/C/populate.sh
gtk2/C/populate.sh
jni/C/populate.sh
libc/C/populate.sh

আমি পরে কীভাবে শর্তগুলি সরিয়ে ফেলা যায় তাও জানি। অর্থাৎ এক স্তর নীচে যাচ্ছে:

cd x86-headers
for x in */C/populate.sh; do i=${x%%/*}; echo $i; done

দেয়

elf
gl
gmp
gnome2
gtk2
jni
libc

তবে, এগুলিকে একত্রিত করার চেষ্টা করা কার্যকর নয়। অর্থাত

for x in x86-headers/*/C/populate.sh; do i=${${x##x86-headers}%%/*}; echo $i; done

দেয়

bash: ${${x##x86-headers}%%/*}: bad substitution

সন্দেহ নেই যে এটি ভুল বাক্য গঠন, তবে আমি সঠিক বাক্য গঠন জানি না। অবশ্যই এটি করার আরও ভাল উপায় থাকতে পারে। যদি আমি পাইথন ব্যবহার করতাম, তবে /প্রতিটি পাথকে তালিকায় ভাঙতে আমি বিভাজনটি ব্যবহার করতাম এবং তারপরে দ্বিতীয় উপাদানটি বাছাই করতাম, তবে কীভাবে বাশ করতে হয় তা আমি জানি না।

সম্পাদনা: উত্তরের জন্য ধন্যবাদ। আমারও জিজ্ঞাসা করা উচিত ছিল, এই বহনযোগ্যভাবে করা সম্ভব, এবং যদি তাই হয়, কিভাবে?

উত্তর:


9

আপনি bashএগুলি (বা পসিক্সলি) এর সাথে একত্রিত করতে পারবেন না , আপনাকে এটি দুটি ধাপে করতে হবে।

i=${x#*/}; i=${i%%/*}

এটি কোনও পসিক্স শেলের পোর্টেবল। যদি আপনার বোর্ন শেলটির বহনযোগ্যতা প্রয়োজন (তবে আপনি কেন নিজের প্রশ্ন / বাশকে ট্যাগ করবেন ?) পাশাপাশি আপনি সোলারিসে পোর্ট করছেন এবং সেখানে /bin/shমানের পরিবর্তে ব্যবহার করতে বাধ্য হন shবা 20 বছরের পুরানো সিস্টেমে পোর্টিং করতে পারেন) , আপনি এই পদ্ধতির ব্যবহার করতে পারেন (যা পসিক্স শেলগুলির সাথে কাজ করবে):

IFS=/; set -f
set x $x
i=$3

(উপরেরটি খুব বিরল ক্ষেত্রে এর মধ্যে একটি যেখানে ভেরিয়েবলটি অব্যক্ত রাখার অর্থ হয়)।

কেবল রেকর্ডের জন্য, zsh সহ:

print -rl -- x86-headers/*/C/populate.sh(:h:h:t)

( T এর পীড়িত এর EAD ফাইলের EAD)।

বা আপনার pythonপদ্ধতির জন্য:

x=elf/C/populate.sh
i=${${(s:/:)x}[2]}

সেমিকোলনটি option i=${x#*/}; i=${i%%/*}চ্ছিক, তাই না?
দিমিত্রে রাদৌলভ

3
@ দিমিত্রেআরডলভ এটি alচ্ছিক তবে কিছু শেলগুলি / এর কিছু পুরানো সংস্করণেরashdash মতো অ্যাসাইনমেন্টগুলি ডান থেকে বামে চালিত করবে (যা বোর্ন শেলটি কীভাবে আচরণ করেছিল) এবং এই ক্ষেত্রে সমস্যা সৃষ্টি করে।
স্টাফেন চেজেলাস

7

প্যারামিটার সম্প্রসারণ আপনাকে বাসা বাঁধার অনুমতি দেয় না, তাই আপনি একটি নিয়োগ সহ দুটি পদক্ষেপে এটি করতে বাধ্য হন:

i=${x##x86-headers/}
i=${i%%/*}

আপনার কাছে এখানে অ্যারে ব্যবহারের বিকল্প রয়েছে তবে আমি মনে করি এটি উপরের পিইর চেয়ে আরও জটিল হবে:

IFS=/
set -f # Disable globbing in case unquoted $x has globs in it
i=( $x )
set +f
echo "${i[1]}"

তারপরে বাহ্যিক কমান্ড ব্যবহারের তৃতীয় বিকল্প রয়েছে। ফাইলগুলির একটি সংক্ষিপ্ত তালিকা সহ এটি সাধারণত সবচেয়ে স্বল্প দক্ষ বিকল্প, তবে ফাইলের সংখ্যা বাড়ার সাথে সাথে এটি সর্বোত্তম স্কেল করবে:

# For clarity, assume no names have linebreaks in them
find . -name populate.sh | cut -d / -f 3

এটি যদিও সমস্ত শাঁসের ক্ষেত্রে সত্য নয়, zshবাসা বাঁধার অনুমতি দেয়।
স্টাফেন চেজেলাস

3
@ স্টাফেন চ্যাজেলাস যথেষ্ট মেলা, তবে এই প্রশ্নটি ট্যাগ করা bash
কোজিরো

2
regex="x86-headers/([^/]*)/.*"
for f in x86-headers/*/C/populate.sh; do [[ $f =~ $regex ]] && echo "${BASH_REMATCH[1]}"; done
elf
gl
gmp
gnome2
gtk2
jni
libc

2

বেলো হিসাবে একটি কনস্ট্রাক্ট ব্যবহার করে খুব সতর্কতা অবলম্বন করুন:

# What happen if no files match ?
for x in x86-headers/*/C/populate.sh; do
  x=${x##x86-headers/}
  x=${x%%/*}
  echo $x
done

আপনি একটি কাজ শেষ হতে পারে হিসাবে echo *। এই ক্ষেত্রে, এটি শুধুমাত্র মজার, কিন্তু এটা অনেক খারাপ কিছু হতে পারে যদি আপনার রুট, আপনার দ্বারা CWDহয় /এবং আপনি কিছু সাব ডিরেক্টরি মুছে ফেলতে চান /tmpতাদের অনুনাদী পরিবর্তে!

ব্যাশে এটি ঠিক করতে, আপনি এটি করতে পারেন:

shopt -s nullglob
for x in x86-headers/*/C/populate.sh; do
  x=${x##x86-headers/}
  x=${x%%/*}
  echo $x
done
shopt -u nullglob

shopt -u nullglobলুপের পরে ডিফল্ট ব্যাশ আচরণ পুনরুদ্ধার করতে শেষে লক্ষ্য করুন ।

আরও বহনযোগ্য সমাধান হতে পারে:

for x in x86-headers/*/C/populate.sh; do
  [ -e $x ] || break
  x=${x##x86-headers/}
  x=${x%%/*}
  echo $x
done

( ##এবং %%প্যারামিটার খেলোয়াড় মধ্যে বৈধ ksh88 )।

নালাগ্লোব সম্পর্কে আরও সম্পূর্ণ আলোচনার জন্য এই লিঙ্কটি অনুসরণ করুন ।

লক্ষ করুন যে উপরের 3 টি সমাধান ব্যর্থ হয় যদি আপনার নামের সাথে একটি স্থান সহ কোনও মধ্যস্থ ডিরেক্টরি থাকে। এটির সমাধানের জন্য, পরিবর্তনশীল বিকল্পটিতে ডাবল-কোট ব্যবহার করুন:

for x in x86-headers/*/C/populate.sh; do
  [ -e "$x" ] || break
  x="${x##x86-headers/}"
  x="${x%%/*}"
  echo "$x"
done

0

পোর্টের নামগুলিতে প্যাটার্ন ম্যাচিং করার জন্য আপনি IFSশেল ভেরিয়েবলটি সেট করতে পারেন /এবং তারপরে শেল প্যারামিটার এক্সপেনশন ব্যবহার করতে পারেন ।

এই সমস্ত কিছু সাবশেলে করা পিতামাতার শেলের পরিবেশ অপরিবর্তিত রাখতে সহায়তা করে!

# cf. "The real Bourne shell problem",
# http://utcc.utoronto.ca/~cks/space/blog/programming/BourneShellLists

paths='
x86-headers/elf/C/populate.sh
x86-headers/gl/C/populate.sh
x86-headers/gmp/C/populate.sh
x86-headers/gnome2/C/populate.sh
x86-headers/gtk2/C/populate.sh
x86-headers/jni/C/populate.sh
x86-headers/libc/C/populate.sh
'

IFS='
'

# version 1
for x in $paths; do 
   ( IFS='/'; set -- ${x}; echo "$2" ); 
done


# version 2
set -- ${paths}
for x in $@; do 
   ( IFS='/'; set -- ${x}; echo "$2" ); 
done
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.