পরিবর্তনশীল সম্প্রসারণ স্থগিত করার উপায়


18

আমি আমার স্ক্রিপ্টের শীর্ষে ভেরিয়েবলগুলি দিয়ে কিছু স্ট্রিং সূচনা করতে চেয়েছিলাম যা এখনও সেট করা হয়নি, যেমন:

str1='I went to ${PLACE} and saw ${EVENT}'
str2='If you do ${ACTION} you will ${RESULT}'

এবং তারপর পরে PLACE, EVENT, ACTION, এবং RESULTসেট হবে। আমি তারপরে ভেরিয়েবলগুলি প্রসারিত করে আমার স্ট্রিংগুলি মুদ্রণ করতে সক্ষম হতে চাই। আমার একমাত্র বিকল্প eval? এটি কাজ করে বলে মনে হচ্ছে:

eval "echo ${str1}"

এই মান? এই কাজ করতে একটি ভাল উপায় আছে কি? evalভেরিয়েবল কিছু হতে পারে তা বিবেচনা করে চালানো ভাল হবে না nice

উত্তর:


23

আপনি যে ধরণের ইনপুট দেখান সেগুলি দিয়ে স্ট্রিংয়ের পরিবর্তে মানগুলি প্রতিস্থাপনের শেল সম্প্রসারণের একমাত্র উপায় হ'ল evalকিছু ফর্ম ব্যবহার করা। এটি ততক্ষণ সুরক্ষিত থাকবে যতক্ষণ আপনি এর মান নিয়ন্ত্রণ করেন str1এবং নিশ্চিত করতে পারেন যে এটি কেবলমাত্র ভেরিয়েবলগুলি রেফার করে যা নিরাপদ হিসাবে পরিচিত (গোপনীয় তথ্য না থাকা) এবং অন্য কোনও শত্রু শেল বিশেষ অক্ষর নেই contain আপনার ডাবল উদ্ধৃতিতে বা একটি এখানে নথিতে স্ট্রিংটি প্রসারিত করা উচিত, কেবলমাত্র "$\`সেই পথটিই বিশেষ (তাদের একটি \ইন এর আগে হওয়া দরকার str1)।

eval "substituted=\"$str1\""

স্ট্রিংয়ের পরিবর্তে কোনও ফাংশন সংজ্ঞায়িত করা আরও অনেক বেশি দৃust় হবে।

fill_template () {
  sentence1="I went to ${PLACE} and saw ${EVENT}"
  sentence2="If you do ${ACTION} you will ${RESULT}"
}

ভেরিয়েবল সেট করুন তারপরে fill_templateআউটপুট ভেরিয়েবলগুলি সেট করতে ফাংশনটিতে কল করুন ।

PLACE=Sydney; EVENT=fireworks
ACTION='not learn from history'; RESULT='have to relive history'
fill_template
echo "During my holidays, $sentence1."
echo "Cicero said: \"$sentence2\"."

2
মূল্যায়ন বিলম্ব করতে, এবং স্পষ্টভাবে স্পষ্ট কল এড়াতে একটি ফাংশন ব্যবহার করে দুর্দান্ত কাজ।
ক্লেটন স্ট্যানলে

ভাল সমাধান, এটি আমাকে অনেক সাহায্য করেছে। ধন্যবাদ!
স্টুয়ার্ট

8

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

এটি সত্য, @ গিলস খুব কাছাকাছি এসেছেন তবে তিনি সম্ভবত মূল্যবোধের ওভাররাইডিংয়ের সমস্যা এবং আপনার যদি একাধিকবার প্রয়োজন হয় তবে কীভাবে সেগুলি ব্যবহার করা উচিত সে সমস্যার সমাধান করেন না। সর্বোপরি, একটি টেম্পলেট একাধিকবার ব্যবহার করা উচিত, তাই না?

আমি মনে করি এটি যে ক্রমে আপনি মূল্যায়ন করেছেন এটি আরও গুরুত্বপূর্ণ that's নিম্নোক্ত বিবেচনা কর:

শীর্ষ

এখানে আপনি কিছু ডিফল্ট সেট করবেন এবং কল করার সময় সেগুলি মুদ্রণের জন্য প্রস্তুত হবেন ...

#!/bin/sh
    _top_of_script_pr() ( 
        IFS="$nl" ; set -f #only split at newlines and don't expand paths
        printf %s\\n ${strings}
    ) 3<<-TEMPLATES
        ${nl=
}
        ${PLACE:="your mother's house"}
        ${EVENT:="the unspeakable."}
        ${ACTION:="heroin"}
        ${RESULT:="succeed."}
        ${strings:="
            I went to ${PLACE} and saw ${EVENT}
            If you do ${ACTION} you will ${RESULT}
        "}
    #END
    TEMPLATES

MIDDLE

আপনি অন্য ফাংশনগুলির ফলাফলের উপর ভিত্তি করে মুদ্রণ ফাংশনটিতে কল করার জন্য এটি নির্ধারণ করেছেন ...

    EVENT="Disney on Ice."
    _more_important_function() { #...some logic...
        [ $((1+one)) -ne 2 ] && ACTION="remedial mathematics"
            _top_of_script_pr
    }
    _less_important_function() { #...more logic...
        one=2
        : "${ACTION:="calligraphy"}"
        _top_of_script_pr
    }

থেকে BOTTOM

আপনার এখন এটি সমস্ত সেটআপ হয়ে গেছে, সুতরাং আপনি এখানে ফলাফলগুলি কার্যকর করবেন এবং টানবেন।

    _less_important_function
    : "${PLACE:="the cemetery"}" 
    _more_important_function
    : "${RESULT:="regret it."}" 
    _less_important_function    

ফলাফল

আমি কেন এক মুহুর্তের মধ্যে চলে যাব, তবে উপরোক্ত চালনা করলে নিম্নলিখিত ফলাফল পাওয়া যায়:

_less_important_function()'s প্রথম রান:

আমি তোমার মায়ের বাড়িতে গিয়ে দেখলাম ডিজনি অন আইস।

আপনি যদি ক্যালিগ্রাফি করেন তবে আপনি সফল হবেন।

তারপর _more_important_function():

আমি কবরস্থানে গিয়ে দেখি ডিজনি অন আইস।

যদি আপনি না নিরাময়কারী গণিত আপনি সফল হবে।

_less_important_function() আবার

আমি কবরস্থানে গিয়ে দেখি ডিজনি অন আইস।

প্রতিকারমূলক গণিতটি করলে আপনি আফসোস করবেন

কিভাবে এটা কাজ করে:

এখানে মূল বৈশিষ্ট্যটি হ'ল ধারণাটি হ'ল conditional ${parameter} expansion.আপনি যদি কোনও ফর্মটি ব্যবহার করে সেট না করে বা নাল হয় তবেই কোনও মানকে একটি পরিবর্তনশীল সেট করতে পারেন:

${var_name: =desired_value}

পরিবর্তে আপনি যদি কেবল একটি আনসেট ভেরিয়েবল সেট করতে চান তবে আপনি বাদ পড়বেন :colonএবং নাল মানগুলি যেমন থাকবে তেমন থাকবে।

স্কোপ অন:

আপনি লক্ষ্য করতে পারেন যে উপরের উদাহরণে $PLACEএবং ইতিমধ্যে ডাকা হলেও এটির $RESULTমাধ্যমে সেট করার সময় পরিবর্তিত হয়ে উঠবেন, সম্ভবত এটি চালানোর সময় সেগুলি সেট করুন। এটি কাজ করার কারণটি হ'ল এটি একটি ফাংশন - আমি অন্যের জন্য ব্যবহৃত না হয়ে এটি এটিকে ঘিরে রেখেছি । যেহেতু এটিকে একটি সাবশেলে ডাকা হয়, তাই এটি নির্ধারিত প্রতিটি পরিবর্তনশীল হয় এবং এটি তার পিতামাতার শেলের কাছে ফিরে আসে সেই মানগুলি অদৃশ্য হয়ে যায়।parameter expansion_top_of_script_pr()_top_of_script_pr()( subshelled )parens{ curly braces }locally scoped

কিন্তু _more_important_function()সেটগুলি যখন $ACTIONএটি হয় globally scopedতখন এটি _less_important_function()'sদ্বিতীয় মূল্যায়ণকে প্রভাবিত করে $ACTIONকারণ কেবলমাত্র মাধ্যমে _less_important_function()সেট করে$ACTION${parameter:=expansion}.

:খালি

আর কেনই বা আমি নেতৃস্থানীয় ব্যবহার করবেন :colon?ওয়েল, manআপনি যে পৃষ্ঠাটি বলবে যে : does nothing, gracefully.আপনি দেখুন, parameter expansionএটা - ঠিক কি এটা মনে হয় expandsএর মান ${parameter}.যখন আমরা একটি পরিবর্তনশীল সাথে সেট সুতরাং ${parameter:=expansion}আমরা তার মান অবশিষ্ট করছি - যা শেল ইচ্ছা ইন-লাইন কার্যকর করার চেষ্টা যদি এটি চালানোর চেষ্টা the cemeteryকরে তবে এটি আপনাকে কিছু ত্রুটি করবে। PLACE="${PLACE:="the cemetery"}"একই ফলাফল উত্পাদন করতে পারে, তবে এটি এই ক্ষেত্রেও নিষ্প্রয়োজন এবং আমি শেলটি পছন্দ করি: ${did:=nothing, gracefully}.

এটি আপনাকে এটি করার অনুমতি দেয়:

    echo ${var:=something or other}
    echo $var
something or other
something or other

এখানে-ডকুমেন্টস

এবং যাইহোক - নাল বা আনসেট ভেরিয়েবলের ইন-লাইন সংজ্ঞাটিও কেন নিম্নলিখিত কাজ করে:

    <<HEREDOC echo $yo
        ${yo=yoyo}
    HEREDOC
yoyo

here-document এটিকে ভাবার সর্বোত্তম উপায় হ'ল একটি ইনপুট ফাইল-বর্ণনাকারীর কাছে প্রবাহিত একটি আসল ফাইল। কমবেশি তারা যা তা হয় তবে বিভিন্ন শেল এগুলি কিছুটা ভিন্নভাবে প্রয়োগ করে।

যাইহোক, <<LIMITERআপনি যদি উদ্ধৃতি না দিয়ে থাকেন তবে আপনি এটির প্রবাহিত এবং মূল্যায়ন করুন expansion.সুতরাং একটি ভেরিয়েবল ঘোষণা করে here-documentকাজ করতে পারে তবে কেবল expansionযার মাধ্যমে আপনি কেবল ইতিমধ্যে সেট না করে কেবল চলকগুলি সেট করতে সীমাবদ্ধ করেন। তবুও, আপনি যেমন বর্ণনা করেছেন তেমন এটি আপনার প্রয়োজনের সাথে পুরোপুরি ফিট করে, কারণ আপনি যখন আপনার টেম্পলেট মুদ্রণ ফাংশনটি কল করেন তখন আপনার ডিফল্ট মানগুলি সর্বদা সেট হয়ে যায়।

কেন না eval?

ঠিক আছে, আমি যে উদাহরণটি উপস্থাপন করেছি parameters.তা গ্রহণের একটি নিরাপদ এবং কার্যকর উপায় সরবরাহ করে কারণ এটি সুযোগকে পরিচালনা করে, ${parameter:=expansion}সেটগুলির মধ্যে প্রতিটি পরিবর্তনশীল বাইরে থেকে নির্ধারণযোগ্য । সুতরাং, আপনি যদি এই সমস্ত কিছু টেমপ্লেট_পিআরশ নামক স্ক্রিপ্টে রেখে দেন এবং চালিত হন:

 % RESULT=something_else template_pr.sh

আপনি পাবেন:

আমি তোমার মায়ের বাড়িতে গিয়ে দেখলাম ডিজনি অন আইস

আপনি যদি ক্যালিগ্রাফি করেন তবে কিছু হবে _

আমি কবরস্থানে গিয়ে দেখি ডিজনি অন আইস

আপনি যদি প্রতিকারমূলক গণিত করেন তবে আপনি কিছু_হেতু করবেন

আমি কবরস্থানে গিয়ে দেখি ডিজনি অন আইস

আপনি যদি প্রতিকারমূলক গণিত করেন তবে আপনি কিছু_হেতু করবেন

এটি স্ক্রিপ্টে আক্ষরিকভাবে সেট করা সেই পরিবর্তনশীলগুলির জন্য কাজ করবে না, $EVENT, $ACTION,এবং $one,তবে আমি পার্থক্যটি প্রদর্শনের জন্য কেবল সেগুলি সংজ্ঞায়িত করেছি।

যাই হোক না কেন, একটি evaledবিবৃতিতে অজানা ইনপুট গ্রহণযোগ্যতা সহজাতভাবে অনিরাপদ, যদিও parameter expansionএটি করার জন্য বিশেষভাবে ডিজাইন করা হয়েছে।


1

আপনি স্ট্রিং টেম্পলেটগুলির জন্য অপরিবর্তিত ভেরিয়েবলের পরিবর্তে স্থানধারক ব্যবহার করতে পারেন। এটি খুব দ্রুত অগোছালো হয়ে উঠবে। আপনি যা করছেন তা খুব টেমপ্লেট ভারী হলে আপনি একটি বাস্তব টেম্পলেট লাইব্রেরি সহ কোনও ভাষা বিবেচনা করতে চাইতে পারেন।

format_template() {
    changed_str=$1

    for word in $changed_str; do
        if [[ $word == %*% ]]; then
            var="${word//\%/}"
            changed_str="${changed_str//$word/${!var}}"
        fi
    done
}

str1='I went to %PLACE% and saw %EVENT%'
PLACE="foo"
EVENT="bar"
format_template "$str1"
echo "$changed_str"

উপরের দিকের দিকটি হ'ল টেম্পলেট ভেরিয়েবলটি অবশ্যই এটি নিজস্ব শব্দ (যেমন আপনি করতে পারবেন না "%prefix%foo") be এটি কিছু সংশোধন করে বা কেবল গতিশীল হওয়ার পরিবর্তে টেম্পলেট পরিবর্তনশীলটিকে হার্ড-কোডিং দিয়ে স্থির করা যেতে পারে।

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