কীভাবে একটি শেল কমান্ডকে সেড এক্সপ্রেশনটিতে এম্বেড করা যায়?


16

নিম্নলিখিত ফর্ম্যাট সহ আমার কাছে একটি পাঠ্য ফাইল রয়েছে:

keyword value
keyword value
...

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

সেডের সাহায্যে কীওয়ার্ড এবং মান অংশগুলি মেলানো সহজ

input='
keyword value value
keyword "value  value"
keyword `uname`
'

echo "$input"|sed -e 's/^\([^[:space:]]*\)[[:space:]]\(.*\)$/k=<\1> v=<\2>/'

যা উত্পাদন করে

k=<keyword> v=<value value>
k=<keyword> v=<"value  value">
k=<keyword> v=<`uname`>

তবে তারপরে প্রশ্নটি হল আমি কীভাবে শেড এক্সপ্রেশনটির প্রতিস্থাপনের অংশে একটি শেল কমান্ড এম্বেড করতে পারি। এই ক্ষেত্রে আমি প্রতিস্থাপন হতে চাই \1 `echo \2`


আহ ... আমি উত্তর হিসাবে এটি দেওয়ার মতো নিশ্চিত নই, তবে সেডের সাথে উদ্ধৃত ডাবল ব্যবহার করা আপনাকে অভিব্যক্তির ভিতরে শেল $ (কমান্ড) বা $ ভেরিয়েবল ব্যবহার করা উচিত।
St0rM

উত্তর:


18

স্ট্যান্ডার্ড শেড শেল কল করতে পারে না ( জিএনইউ সেড এটি করার জন্য একটি এক্সটেনশন রয়েছে , যদি আপনি কেবল অ-এমবেডড লিনাক্সের বিষয়ে চিন্তা করেন), সুতরাং আপনাকে বাইরে কিছু সেড প্রসেসিং করতে হবে। বেশ কয়েকটি সমাধান রয়েছে; সবার সাবধানতার সাথে উদ্ধৃতি দেওয়া দরকার।

আপনি মানগুলি কীভাবে প্রসারিত করতে চান তা ঠিক এটি পরিষ্কার নয়। উদাহরণস্বরূপ, যদি একটি লাইন হয়

foo hello; echo $(true)  3

নিচের কোনটি আউটপুট হওয়া উচিত?

k=<foo> value=<hello; echo   3>
k=<foo> value=<hello; echo   3>
k=<foo> value=<hello; echo 3>
k=<foo> value=<foo hello
  3>

আমি নীচে বেশ কয়েকটি সম্ভাবনা নিয়ে আলোচনা করব।

খাঁটি শেল

আপনি লাইন দ্বারা ইনপুট লাইনটি পড়তে এবং এটি প্রক্রিয়া করতে শেলটি পেতে পারেন। এটি সহজ সমাধান এবং সংক্ষিপ্ত ফাইলের জন্য দ্রুততমও। এটি আপনার প্রয়োজনের নিকটতম জিনিস " echo \2":

while read -r keyword value; do
  echo "k=<$keyword> v=<$(eval echo "$value")>"
done

read -r keyword value$keywordলাইনের প্রথম সাদা স্থান-বিস্মৃত শব্দটি সেট করে এবং$value বাকী লাইন বিয়োগের পিছনে হোয়াইটস্পেসে অনুসরণ করে।

আপনি যদি ভেরিয়েবল রেফারেন্সগুলি প্রসারিত করতে চান তবে কমান্ড বিকল্পের বাইরে কমান্ডগুলি কার্যকর না করে $valueএকটি নথির ভিতরে রাখুন । আমার সন্দেহ হয় আপনি সত্যই এটি খুঁজছিলেন।

while read -r keyword value; do
  echo "k=<$keyword> v=<$(cat <<EOF
$value
EOF
)>"
done

একটি খোল মধ্যে পাইপ পাইপ

আপনি ইনপুটটিকে শেল স্ক্রিপ্টে রূপান্তর করতে পারেন এবং এটি মূল্যায়ন করতে পারেন। শেড টাস্ক আপ, যদিও এটি এত সহজ নয়। আপনার " echo \2" প্রয়োজনীয়তার সাথে যাচ্ছেন (নোট করুন যে কীওয়ার্ডে আমাদের একক উদ্ধৃতিগুলি এড়াতে হবে):

sed  -e 's/^ *//' -e 'h' \
     -e 's/[^ ]*  *//' -e 'x' \
     -e 's/ .*//' -e "s/'/'\\\\''/g" -e "s/^/echo 'k=</" \
     -e 'G' -e "s/\n/>' v=\\</" -e 's/$/\\>/' | sh

এখানে একটি দস্তাবেজ নিয়ে যেতে, আমাদের এখনও কীওয়ার্ডটি (তবে ভিন্নভাবে) এড়িয়ে চলতে হবে।

{
  echo 'cat <<EOF'
  sed -e 's/^ */k=</' -e 'h' \
      -e 's/[^ ]*  *//' -e 'x' -e 's/ .*//' -e 's/[\$`]/\\&/g' \
      -e 'G' -e "s/\n/> v=</" -e 's/$/>/'
  echo 'EOF'
 } | sh

আপনার কাছে প্রচুর ডেটা থাকলে এটি দ্রুততম পদ্ধতি: এটি প্রতিটি লাইনের জন্য পৃথক প্রক্রিয়া শুরু করে না।

awk

আমরা একই কাজটি এসডির সাথে সিড ওয়ার্কের সাথে ব্যবহার করেছি। ফলস্বরূপ প্রোগ্রামটি যথেষ্ট বেশি পঠনযোগ্য। " echo \2" এর সাথে যাচ্ছি :

awk '
  1 {
      kw = $1;
      sub(/^ *[^ ]+ +/, "");
      gsub(/\047/, "\047\\\047\047", $1);
      print "echo \047k=<" kw ">\047 v=\\<" $0 "\\>";
  }' | sh

এখানে একটি নথি ব্যবহার:

awk '
  NR==1 { print "cat <<EOF" }
  1 {
      kw = $1;
      sub(/^ *[^ ]+ +/, "");
      gsub(/\\\$`/, "\\&", $1);
      print "k=<" kw "> v=<" $0 ">";
  }
  END { print "EOF" }
' | sh

দুর্দান্ত উত্তর আমি খাঁটি শেল সমাধানটি ব্যবহার করতে যাচ্ছি, কারণ ইনপুট ফাইলটি আসলেই ছোট এবং কার্য সম্পাদন কোনও উদ্বেগ নয়, এটি পরিষ্কার এবং পাঠযোগ্যও able
আর্নেস্ট এসি

একটি হ্যাক একটি বিট কিন্তু যথেষ্ট ঝরঝরে। উদাহরণস্বরূপ লম্বা হেক্স স্ট্রিংটি ডিকোড করতে এক্সএক্সডি কল করতে সিড ব্যবহার করুন। । । বিড়াল FtH.ch13 | sed -r 's /(.* পাঠ্য। *: [) ([0-9a-fA-F] *)] / \ 1 $ (প্রতিধ্বনি \ 2 | xxd -r -p)] /; এস / ^ ( । *) e / প্রতিধ্বনি "\ 1" / g '| বাশ> FtHtext.ch13 যেখানে ফিটএইচ.এইচ 13 এর "ফু ফু হেক্স পাঠ্য পরীক্ষার মতো লাইন রয়েছে: [666f6f0a62617200]"
গায়োথে 12'8

14

GNU থাকলে sedআপনি নিম্নলিখিত কমান্ডটি ব্যবহার করতে পারেন:

sed -nr 's/([^ ]+) (.*)/echo "\1" \2\n/ep' input

কোন ফলাফল:

keyword value value
keyword value  value
keyword Linux

আপনার ইনপুট ডেটা সহ।

ব্যাখ্যা:

সেড কমান্ড -nঅপশনটি ব্যবহার করে নিয়মিত আউটপুট দমন করে । -rবর্ধিত নিয়মিত এক্সপ্রেশন ব্যবহার করার জন্য পাস করা হয় যা আমাদের ধরণে বিশেষ অক্ষরের কিছুটা পালাতে বাঁচায় তবে এটির প্রয়োজন নেই।

sকমান্ড কমান্ড মধ্যে ইনপুট লাইন স্থানান্তর করতে ব্যবহার করা হয়:

echo "\1" \2

কীওয়ার্ডটির মানটি উদ্ধৃত হয়নি। আমি কমান্ডটি e- যা জিএনইউ নির্দিষ্ট - এই বিকল্পটি পাস করেছি s, যা শেল কমান্ড হিসাবে প্রতিস্থাপনের ফলাফলটি সম্পাদন করতে বলে এবং এর ফলাফলটি প্যাটার্ন বাফারে পড়ায় (এমনকি একাধিক লাইন)। বিকল্প ব্যবহার pপরে (!) eকরে তোলে sedপ্যাটার্ন বাফার মুদ্রণ পর কমান্ড মৃত্যুদন্ড কার্যকর করা হয়েছে।


আপনি উভয় -nএবং pবিকল্পগুলি ছাড়া করতে পারেন sed -r 's/([^ ]+) (.*)/echo "\1" \2\n/e' input। তবে এর জন্য ধন্যবাদ! আমি eবিকল্প সম্পর্কে জানতাম না ।
দক্ষ মোদী

@ কাউশালমোদি ওহ হ্যাঁ, আপনি ঠিক বলেছেন! eবিকল্পটি আসার সময় আমি বেড়াতে বসে আছি (জিএনইউ দ্বারা প্রবর্তিত)। তা কি এখনও আছে sed? :)
hek2mgl

ঠিক আছে, এটা আমার জন্য কাজ করেছে। এটি RHEL বিতরণে আমার (GNU সেড সংস্করণ 4.2.1) ডিফল্টরূপে GNU সেড।
দক্ষ মোদী

4

আপনি এই পদ্ধতির চেষ্টা করতে পারেন:

input='
keyword value value
keyword "value  value"
keyword `uname`
'

process() {
  k=$1; shift; v="$*"
  printf '%s\n' "k=<$k> v=<$v>"
}

eval "$(printf '%s\n' "$input" | sed -n 's/./process &/p')"

(যদি আমি আপনার উদ্দেশ্যটি সঠিকভাবে পাই)। এটি প্রতিটি খালি খালি লাইনের শুরুতে "প্রক্রিয়া" সন্নিবেশ করান যাতে এটি স্ক্রিপ্ট তৈরি করে:

process keyword value value
process keyword "value  value"
process keyword `uname`

মূল্যায়ন করতে হবে ( eval) যেখানে প্রক্রিয়া এমন একটি ফাংশন যা প্রত্যাশিত বার্তাটি প্রিন্ট করে।


1

যদি একটি নন-সিড সমাধান গ্রহণযোগ্য হয় তবে এই পার্ল স্নিপেটটি কাজটি করবে:

$ echo "$input" | perl -ne 'chomp; /^\s*(.+?)\s+(.+)$/ && do { $v=`echo "$2"`; chomp($v); print "k=<$1> v=<$v>\n"}'

1
ধন্যবাদ তবে আমি বরং অন্য স্ক্রিপ্টিং ভাষা ব্যবহার করা এড়াতে চাই যদি আমি এটি স্ট্যান্ডার্ড ইউনিক্স কমান্ড এবং বর্ন শেল রাখতে পারি
আর্নেস্ট এসি

0

কেবল কিসস শর্ট খাঁটি বীজ

আমি এটা করব

echo "ls_me" | sed -e "s/\(ls\)_me/\1/e" -e "s/to be/continued/g;"

এবং এটি কাজ করে।


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