কমান্ড প্রতিস্থাপনের মাধ্যমে আমি অন্য কমান্ডে কীভাবে যুক্তি উত্পন্ন করতে পারি


11

থেকে অনুসরণ করা: শেল কমান্ড প্রতিস্থাপনে অপ্রত্যাশিত আচরণ

আমার একটি কমান্ড রয়েছে যা যুক্তিগুলির একটি বিশাল তালিকা নিতে পারে, যার মধ্যে কয়েকটি বৈধভাবে স্পেস থাকতে পারে (এবং সম্ভবত অন্যান্য জিনিসগুলি)

আমি একটি স্ক্রিপ্ট লিখেছিলাম যা আমার জন্য উক্ত আর্গুমেন্ট উত্পন্ন করতে পারে, উদ্ধৃতি সহ, তবে আমাকে অবশ্যই অনুলিপি করে আউটপুটটি আটকানো উচিত

./somecommand
<output on stdout with quoting>
./othercommand some_args <output from above>

আমি খালি কাজ করে এটি প্রবাহিত করার চেষ্টা করেছি

./othercommand $(./somecommand)

এবং উপরের প্রশ্নে উল্লিখিত অপ্রত্যাশিত আচরণে ছুটে এসেছি। প্রশ্নটি হ'ল - othercommandকিছু আর্গুমেন্টের উদ্ধৃতি আবশ্যক এবং এটি পরিবর্তন করা যায় না যে যুক্তি উত্পন্ন করতে কমান্ড বিকল্পটি নির্ভরযোগ্যভাবে ব্যবহার করা যেতে পারে?


"নির্ভরযোগ্যভাবে" আপনি কী বোঝাতে চান তার উপর নির্ভর করে। আপনি যদি পরবর্তী কমান্ডটি আউটপুটটিকে স্ক্রিনে যেমন প্রদর্শিত হয় ঠিক তেমন গ্রহণ করেন এবং এতে শেল নিয়ম প্রয়োগ করেন, তবে সম্ভবত evalএটি ব্যবহার করা যেতে পারে তবে এটি সাধারণত প্রস্তাবিত নয়। xargs
এটিও

আমি somecommandনিয়মিত শেল
পার্সিংয়ের

আমি আমার উত্তর বলেন, ক্ষেত্র বিভাজন (যেমন জন্য কিছু অন্যান্য চরিত্র ব্যবহার :) ... যে চরিত্র অভিমানী নির্ভরযোগ্যভাবে হবে না আউটপুটে হও।
ওলরিন

তবে এটি সত্যিই সঠিক নয় কারণ এটি উক্ত নিয়মের উদ্ধৃতি দেয় না, যা এটি সম্পর্কে
ইউজার 21207217

2
আপনি একটি বাস্তব বিশ্বের উদাহরণ পোস্ট করতে পারেন? আমি বলতে চাইছি, প্রথম কমান্ডের আসল আউটপুট এবং আপনি কীভাবে এটি দ্বিতীয় কমান্ডের সাথে ইন্টারঅ্যাক্ট করতে চান।
এনএক্সনেভ

উত্তর:


10

আমি একটি স্ক্রিপ্ট লিখেছিলাম যা আমার পক্ষে উক্তি সহ সেই যুক্তি উত্পন্ন করতে পারে

শেলটির জন্য যদি আউটপুটটি সঠিকভাবে উদ্ধৃত হয় এবং আপনি আউটপুটকে বিশ্বাস করেন তবে আপনি এটি চালাতে evalপারেন।

ধরে নিই যে আপনার কাছে একটি শেল রয়েছে যা অ্যারে সমর্থন করে, আপনার আর্গুমেন্টগুলি সংরক্ষণ করার জন্য এটি ব্যবহার করা ভাল।

যদি ./gen_args.shআউটপুট এর মতো উত্পাদিত হয় 'foo bar' '*' asdf, তবে আমরা ফলাফলগুলির সাথে eval "args=( $(./gen_args.sh) )"ডাকা একটি অ্যারে তৈরি করতে দৌড়াতে পারি args। যে তিনটি উপাদান হবে foo bar, *, asdf

"${args[@]}"অ্যারে উপাদানগুলি পৃথকভাবে প্রসারিত করতে আমরা যথারীতি ব্যবহার করতে পারি :

$ eval "args=( $(./gen_args.sh) )"
$ for var in "${args[@]}"; do printf ":%s:\n" "$var"; done
:foo bar:
:*:
:asdf:

(উদ্ধৃতি দ্রষ্টব্য। "${array[@]}"যেমন স্বতন্ত্র আর্গুমেন্ট অপরিবর্তিত সব উপাদান বিস্তৃতি। কোট ছাড়া অ্যারে উপাদানের শব্দ বিভাজন সাপেক্ষে। দেখুন উদাঃ BashGuide উপর অ্যারেগুলির পৃষ্ঠা ।)

যাইহোক , evalআনন্দের সাথে কোনও শেল বিকল্পগুলি চালিত করবে, সুতরাং $HOMEআউটপুটটি আপনার হোম ডিরেক্টরিতে প্রসারিত হবে এবং একটি কমান্ড প্রতিস্থাপনটি শেল চলমান অবস্থায় একটি কমান্ড চালিত করবে eval। এর আউটপুট "$(date >&2)"একটি একক খালি অ্যারে উপাদান তৈরি করবে এবং স্টডআউটে বর্তমান তারিখটি মুদ্রণ করবে। gen_args.shনেটওয়ার্কের উপরের অন্য হোস্টের মতো, অন্যান্য ব্যবহারকারীর দ্বারা নির্মিত ফাইলের নামগুলির মতো কিছু অবিশ্বস্ত উত্স থেকে ডেটা পাওয়া গেলে এটি উদ্বেগজনক । আউটপুটটিতে যথেচ্ছ কমান্ড অন্তর্ভুক্ত থাকতে পারে। (যদি get_args.shনিজেই দূষিত হয় তবে এর কোনও কিছুর আউটপুট দেওয়ার দরকার পড়েনি, এটি সরাসরি দূষিত কমান্ডগুলি চালাতে পারে))


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

আসুন চয়ন করুন #, এবং স্ক্রিপ্ট আউটপুট আছে foo bar#*#asdf। এখন আমরা কমান্ডের আউটপুটটিকে আর্গুমেন্টে বিভক্ত করতে উদ্ধৃত কমান্ড সম্প্রসারণ ব্যবহার করতে পারি ।

$ IFS='#'                          # split on '#' signs
$ set -f                           # disable globbing
$ args=( $( ./gen_args3.sh ) )     # assign the values to the arrayfor var in "${args[@]}"; do printf ":%s:\n" "$var"; done
:foo bar:
:*:
:asdf:

আপনি IFSযদি স্ক্রিপ্টের অন্য কোথাও শব্দ বিভাজনের উপর নির্ভর করে ( unset IFSএটিকে ডিফল্ট হিসাবে তৈরি করার জন্য কাজ করা উচিত) এবং set +fআপনি যদি পরে গ্লোব্বিং ব্যবহার করতে চান তবে ব্যবহার করতে হবে later

আপনি যদি বাশ বা অ্যারে রয়েছে এমন কোনও শেল ব্যবহার না করে থাকেন তবে আপনি তার জন্য অবস্থানগত পরামিতি ব্যবহার করতে পারেন। প্রতিস্থাপন args=( $(...) )সঙ্গে set -- $(./gen_args.sh)এবং ব্যবহার "$@"পরিবর্তে "${args[@]}"তারপর। (এখানেও আপনার চারপাশে উদ্ধৃতি প্রয়োজন "$@", অন্যথায় অবস্থানগত পরামিতিগুলি শব্দ বিভাজনের সাপেক্ষে))


দুই ভুবনের সেরা!
অলরিন

আপনি কি ${args[@]}
উদ্ধৃতিটির

@ ব্যবহারকারী1207217, হ্যাঁ, আপনি ঠিক বলেছেন। এটা তোলে অ্যারে এবং একই জিনিস "${array[@]}"সঙ্গে "$@"। উভয়ই উদ্ধৃত করা দরকার, বা অন্যথায় শব্দ বিভাজনে অ্যারের উপাদানগুলিকে অংশে বিভক্ত করে।
ইল্কাচ্চু

6

সমস্যাটি হ'ল একবার আপনার somecommandস্ক্রিপ্টের জন্য বিকল্পগুলি আউটপুট করে নিলে, বিকল্পগুলি othercommandসত্যই কেবল পাঠ্য হয় এবং শেলের স্ট্যান্ডার্ড পার্সিংয়ের করুণায় থাকে (যা কিছু $IFSঘটে তা দ্বারা প্রভাবিত হয় এবং কোন শেল অপশন কার্যকর হয়, যা আপনি সাধারণ ক্ষেত্রে না করেন) নিয়ন্ত্রণ করা)।

বিকল্পগুলি আউটপুট ব্যবহার somecommandকরার পরিবর্তে, কল করার জন্য এটি ব্যবহার করা সহজ, নিরাপদ এবং আরও দৃust় হবে । স্ক্রিপ্ট তারপর একটি হবে মোড়কের স্ক্রিপ্ট প্রায় পরিবর্তে সাহায্যকারী স্ক্রিপ্ট কিছু বাছাই তোমাদের কমান্ড লাইন অংশ হিসাবে কিছু বিশেষ ভাবে ডাকতে মনে রাখতে হবে যে । র্যাপার স্ক্রিপ্টগুলি এমন একটি সরঞ্জাম সরবরাহের একটি খুব সাধারণ উপায় যা কেবলমাত্র অন্যান্য কিছু অনুরূপ সরঞ্জামকে অপশনগুলির অন্য সেটগুলির সাথে কল করে (কেবলমাত্র কমান্ডগুলি আসলে শেল স্ক্রিপ্টের মোড়ক রয়েছে তা পরীক্ষা করে দেখুন )। othercommandsomecommandothercommandotherscriptfile/usr/bin

ইন bash, kshবা zsh, আপনি সহজেই এমন একটি মোড়ক স্ক্রিপ্ট করতে পারেন যা পৃথক বিকল্পগুলি othercommandপছন্দ করার জন্য অ্যারে ব্যবহার করে :

options=( "hi there" "nice weather" "here's a star" "*" )
options+=( "bonus bumblebee!" )  # add additional option

তারপরে কল করুন othercommand(এখনও মোড়কের স্ক্রিপ্টের মধ্যেই):

othercommand "${options[@]}"

এর প্রসারণটি "${options[@]}"নিশ্চিত করবে যে optionsঅ্যারের প্রতিটি উপাদান পৃথকভাবে উদ্ধৃত হয়েছে এবং othercommandপৃথক যুক্তি হিসাবে উপস্থাপিত হয়েছে ।

মোড়কের ব্যবহারকারী যে এটি আসলে ডাকছে অজ্ঞাত হবে othercommand, এমন কিছু বিষয় যা হবে না সত্য হতে যদি স্ক্রিপ্ট পরিবর্তে ঠিক কমাণ্ড লাইন অপশন সম্বন্ধে উত্পন্ন othercommandআউটপুট।

ইন /bin/sh, $@বিকল্পগুলি ধরে রাখতে ব্যবহার করুন:

set -- "hi there" "nice weather" "here's a star" "*"
set -- "$@" "bonus bumblebee!"  # add additional option

othercommand "$@"

( setঅবস্থানগত পরামিতি সেট করার জন্য ব্যবহৃত কমান্ড $1, $2, $3ইত্যাদি এগুলি কি অ্যারের তোলে আপ $@একটি প্রমিত POSIX শেল হবে। প্রাথমিক --সংকেত হয় setকোন অপশন দেওয়া, শুধুমাত্র আর্গুমেন্ট আছে। --হয় সত্যিই শুধুমাত্র প্রয়োজনে প্রথম মানটি কিছু দিয়ে শুরু হয় -))

মনে রাখবেন এটি চারপাশে দ্বিগুণ উদ্ধৃতি $@এবং ${options[@]}এটি নিশ্চিত করে যে উপাদানগুলি স্বতন্ত্রভাবে শব্দ-বিভক্ত নয় (এবং ফাইলের নাম বিশ্বব্যাপী)।


আপনি ব্যাখ্যা হতে পারে set --?
ব্যবহারকারী1207217

@ user1207217 উত্তরের জন্য যুক্ত করা ব্যাখ্যা।
কুসালানন্দ

4

যদি somecommandআউটপুটটি নির্ভরযোগ্যভাবে ভাল শেল সিনট্যাক্সে থাকে তবে আপনি ব্যবহার করতে পারেন eval:

$ eval sh test.sh $(echo '"hello " "hi and bye"')
hello 
hi and bye

তবে আপনাকে নিশ্চিত হতে হবে যে আউটপুটটির বৈধ উদ্ধৃতি রয়েছে এবং এরকম, অন্যথায় আপনি স্ক্রিপ্টের বাইরে চলমান কমান্ডগুলিও শেষ করতে পারেন:

$ cat test.sh 
for var in "$@"
do
    echo "|$var|"
done
$ ls
bar  baz  test.sh
$ eval sh test.sh $(echo '"hello " "hi and bye"; echo rm *')
|hello |
|hi and bye|
rm bar baz test.sh

দ্রষ্টব্য যে echo rm bar baz test.shস্ক্রিপ্টে পাস করা হয়নি (কারণ ;) এবং এটি একটি পৃথক কমান্ড হিসাবে চালিত হয়েছিল। এটি হাইলাইট করার জন্য আমি |চারপাশে যুক্ত করেছি $var


সাধারণত, আপনি যদি আউটপুটকে পুরোপুরি বিশ্বাস না করতে পারেন তবে somecommandকমান্ড স্ট্রিং তৈরির জন্য আউটপুট নির্ভরযোগ্যভাবে ব্যবহার করা সম্ভব নয়।

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