বাশ টেম্প্লেটিং: বাশের সাথে টেমপ্লেটগুলি থেকে কনফিগারেশন ফাইলগুলি কীভাবে তৈরি করবেন?


134

আমি নিজের ওয়েবসারভারের জন্য অ্যাপাচি এবং পিএইচপি-র জন্য কনফিগারেশন ফাইল তৈরি করতে স্বয়ংক্রিয় করতে একটি স্ক্রিপ্ট লিখছি। আমি CPanel বা ISPConfig এর মতো কোনও জিইউআই ব্যবহার করতে চাই না।

আমার কাছে অ্যাপাচি এবং পিএইচপি কনফিগারেশন ফাইলের কিছু টেম্পলেট রয়েছে। বাশ স্ক্রিপ্টটি টেমপ্লেটগুলি পড়তে হবে, কিছু ফোল্ডারে পরিবর্তনশীল প্রতিস্থাপন এবং আউটপুট পার্সড টেমপ্লেট তৈরি করতে হবে। এটি করার সর্বোত্তম উপায় কী? আমি বিভিন্ন উপায় সম্পর্কে চিন্তা করতে পারেন। কোনটি সেরা বা এর থেকে আরও কিছু ভাল উপায় থাকতে পারে? আমি খাঁটি বাশে এটি করতে চাই (উদাহরণস্বরূপ পিএইচপি এ এটি সহজ)

1) পাঠ্য ফাইলে $ {} স্থানধারককে কীভাবে প্রতিস্থাপন করবেন?

template.txt:

the number is ${i}
the word is ${word}

script.sh:

#!/bin/sh

#set variables
i=1
word="dog"
#read in template one line at the time, and replace variables
#(more natural (and efficient) way, thanks to Jonathan Leffler)
while read line
do
    eval echo "$line"
done < "./template.txt"

বিটিডাব্লু, আমি কীভাবে এখানে আউটপুটটিকে বাহ্যিক ফাইলে পুনর্নির্দেশ করব? ভেরিয়েবলগুলিতে, উক্তিগুলি বললে আমার কি কিছু পালাতে হবে?

2) প্রতিটি ভেরিয়েবলকে এর মান দিয়ে প্রতিস্থাপনের জন্য বিড়াল এবং সিড ব্যবহার করুন:

প্রদত্ত টেমপ্লেট টেক্সট:

The number is ${i}
The word is ${word}

COMMAND:

cat template.txt | sed -e "s/\${i}/1/" | sed -e "s/\${word}/dog/"

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

আপনি কি অন্য কিছু মার্জিত এবং নিরাপদ সমাধান সম্পর্কে ভাবতে পারেন?


উত্তর:


61

আপনি এটি ব্যবহার করতে পারেন:

perl -p -i -e 's/\$\{([^}]+)\}/defined $ENV{$1} ? $ENV{$1} : $&/eg' < template.txt

${...}সংশ্লিষ্ট পরিবেশগত ভেরিয়েবলের সাথে সমস্ত স্ট্রিং প্রতিস্থাপন করতে (এই স্ক্রিপ্টটি চালানোর আগে সেগুলি রপ্তানি করতে ভুলবেন না)।

খাঁটি বাশের জন্য এটি কাজ করা উচিত (ধরে নেওয়া যায় যে ভেরিয়েবলগুলিতে $ {...} স্ট্রিং থাকে না):

#!/bin/bash
while read -r line ; do
    while [[ "$line" =~ (\$\{[a-zA-Z_][a-zA-Z_0-9]*\}) ]] ; do
        LHS=${BASH_REMATCH[1]}
        RHS="$(eval echo "\"$LHS\"")"
        line=${line//$LHS/$RHS}
    done
    echo "$line"
done

। সমাধানটি আর স্থগিত হয় না যদি আরএইচএস কিছু পরিবর্তনশীল উল্লেখ করে যা নিজেই উল্লেখ করে:

#!/bin/bash
line="$(cat; echo -n a)"
end_offset=${#line}
while [[ "${line:0:$end_offset}" =~ (.*)(\$\{([a-zA-Z_][a-zA-Z_0-9]*)\})(.*) ]] ; do
    PRE="${BASH_REMATCH[1]}"
    POST="${BASH_REMATCH[4]}${line:$end_offset:${#line}}"
    VARNAME="${BASH_REMATCH[3]}"
    eval 'VARVAL="$'$VARNAME'"'
    line="$PRE$VARVAL$POST"
    end_offset=${#PRE}
done
echo -n "${line:0:-1}"

সতর্কতা : আমি ব্যাশে NULs এর সাথে সঠিকভাবে ইনপুট হ্যান্ডেল করার উপায় বা পিছনে থাকা নতুন লাইনের পরিমাণ সংরক্ষণ করার উপায় জানি না। শেষ রূপটি যেমন উপস্থাপিত হয় তেমন কারণ শাঁস "প্রেম" বাইনারি ইনপুট:

  1. read ব্যাকস্ল্যাশ ব্যাখ্যা করবে।
  2. read -r ব্যাকস্ল্যাশগুলি ব্যাখ্যা করবে না, তবে এটি যদি নতুন লাইনের সাথে শেষ না হয় তবে শেষ লাইনটি ফেলে দেবে।
  3. "$(…)"যতটা ট্রেলিং করা আছে সেখানে উপস্থিত নিউলাইনগুলি সরিয়ে ফেলবে, তাই আমি শেষ করে ; echo -n aব্যবহার করব echo -n "${line:0:-1}": এটি শেষ চরিত্রটি (যা a) হ্রাস পাবে এবং ইনপুটটিতে যেমন ছিল তেমন অনেকগুলি অনুবর্তনযোগ্য নিউলাইনগুলি সংরক্ষণ করে (না সহ)।

3
আমি পরিবর্তন হবে [^}]থেকে [A-Za-Z_][A-Za-z0-9_](যদি এটি প্রক্রিয়া করার চেষ্টা যেমন কঠোর প্রতিকল্পন বাইরে যাওয়া থেকে খোলসের প্রতিরোধ ব্যাশ সংস্করণে ${some_unused_var-$(rm -rf $HOME)})।
ক্রিস জনসেন

2
@ ফ্র্যাক্টালাইজআর আপনি $&পার্ল সমাধানটিতে পরিবর্তন করতে চাইতে পারেন "": প্রথমে ${...}যদি অভাবিত পাতা ছেড়ে দেয় তবে এটি বিকল্প করতে ব্যর্থ হয়, দ্বিতীয়টি খালি স্ট্রিংয়ের সাথে প্রতিস্থাপন করে।
জাইএক্স

5
দ্রষ্টব্য: স্পষ্টতই ব্যাশ ৩.১ থেকে ৩.২ (এবং উপরে) এর মধ্যে একটি পরিবর্তন হয়েছিল যা রেজেক্সের চারপাশে একক উদ্ধৃতি - রেজেক্সের বিষয়বস্তুকে স্ট্রিং আক্ষরিক হিসাবে বিবেচনা করে। উপরে Regex তাই হওয়া উচিত ... (\ $ \ {[ZA-জেড: _] [ZA-Z_0-9] * \}) stackoverflow.com/questions/304864/...
নীল জলের

2
করতে whileলুপ যদিও তা একটি newline, ব্যবহার দ্বারা সমাপ্ত না শেষ লাইনটি পড়তে while read -r line || [[ -n $line ]]; do। অতিরিক্তভাবে, আপনার readকমান্ড প্রতিটি লাইন থেকে স্বেচ্ছাসেবীকে নেতৃত্ব দেয় এবং অনুসরণ করে; এটি এড়াতে, ব্যবহার করুনwhile IFS= read -r line || [[ -n $line ]]; do
mklement0

2
কেবল বিস্তৃত সমাধানের \ সন্ধানকারীদের জন্য কেবল একটি বাধা লক্ষ করুন: এগুলি অন্যথায় কার্যকর সমাধানগুলি আপনাকে পছন্দসই উল্লেখগুলি প্রসারণ থেকে বাছাই করতে দেয় না (যেমন সেগুলি ছাড়িয়ে রাখার মতো )।
mklement0

138

চেষ্টা envsubst

FOO=foo
BAR=bar
export FOO BAR

envsubst <<EOF
FOO is $FOO
BAR is $BAR
EOF

11
কেবল রেফারেন্সের জন্য, envsubstহেরডোক ব্যবহার করার সময় প্রয়োজনীয় নয় যেহেতু বাশ হেরডোককে আক্ষরিক ডাবল-কোটেড স্ট্রিং হিসাবে বিবেচনা করে এবং এর মধ্যে ইতিমধ্যে ভেরিয়েবলগুলিকে ইন্টারপোলিট করে। আপনি অন্য কোনও ফাইল থেকে টেমপ্লেটটি পড়তে চাইলে এটি দুর্দান্ত পছন্দ। আরও জটিল জন্য একটি ভাল প্রতিস্থাপন m4
বোরপোরার

2
আমি এই আদেশটি জানতে পেরে খুব আনন্দিতভাবে অবাক হয়েছি। আমি শূন্য সাফল্যের সাথে ম্যানুয়ালি এনভাসবস্টের কার্যকারিতা মোচড়ানোর চেষ্টা করছিলাম। ধন্যবাদ ইয়ত্তটস!
টিম স্টুয়ার্ট

4
দ্রষ্টব্য: envsubstএকটি জিএনইউ গেটেক্সটেক্স ইউটিলিটি, এবং এটি আসলে সমস্ত মজবুত নয় (যেহেতু গেটেক্সটেক্সটি মানব বার্তাগুলি স্থানীয়করণের জন্য বোঝানো হয়)। সর্বাধিক গুরুত্বপূর্ণ, এটি ব্যাকস্ল্যাশ-পলাতকৃত {AR VAR} বিকল্পগুলি স্বীকৃতি দেয় না (যাতে আপনার শেল স্ক্রিপ্ট বা এনগিনেক্স কনফ ফাইলের মতো রানটাইমের সময় $ VAR বিকল্প ব্যবহার করতে পারে এমন কোনও টেমপ্লেট থাকতে পারে না)। এমন একটি সমাধানের জন্য আমার উত্তর দেখুন যা ব্যাকস্ল্যাশ পালাতে সক্ষম হয়।
স্টুয়ার্ট পি। বেন্টলে 21

4
@ বিপ্টার এই ক্ষেত্রে, আপনি যদি কোনও কারণে এই টেম্পলেটটি envsubst এ পাস করতে চান তবে আপনি ব্যবহার করতে চান <<"EOF", যা ভেরিয়েবলকে বিভক্ত করে না (উদ্ধৃত টার্মিনেটরগুলি হেরিডোকের একক-কোটের মতো)।
স্টুয়ার্ট পি। বেন্টলে

2
আমি এটির মতো ব্যবহার করেছি: cat template.txt | envsubst
ট্রুথহোল্ডার

47

envsubst আমার জন্য নতুন ছিল। ফ্যান্টাস্টিক।

রেকর্ডের জন্য, একটি কনফিড ফাইল টেম্পলেট করার জন্য হেরেডোক ব্যবহার করা দুর্দান্ত উপায়।

STATUS_URI="/hows-it-goin";  MONITOR_IP="10.10.2.15";

cat >/etc/apache2/conf.d/mod_status.conf <<EOF
<Location ${STATUS_URI}>
    SetHandler server-status
    Order deny,allow
    Deny from all
    Allow from ${MONITOR_IP}
</Location>
EOF

1
কোজের চেয়ে আমি এটিকে আরও ভাল পছন্দ করি envsubstএটি apt-get install gettext-baseআমার ডকফিলিতে অতিরিক্ত থেকে আমার বাঁচিয়েছিল
ট্রুথহোল্ডার

কোনও বাহ্যিক গ্রন্থাগার ইনস্টলেশন না করে বা ছদ্মবেশী অভিব্যক্তি মোকাবেলা করার কারণে চাপ ছাড়াই টেমপ্লেটের মতো স্ক্রিপ্ট হিসাবে শেল।
千 木 郷

35

আমি সেড ব্যবহারের সাথে একমত: এটি অনুসন্ধান / প্রতিস্থাপনের জন্য সেরা হাতিয়ার। এখানে আমার পদ্ধতি:

$ cat template.txt
the number is ${i}
the dog's name is ${name}

$ cat replace.sed
s/${i}/5/
s/${name}/Fido/

$ sed -f replace.sed template.txt > out.txt

$ cat out.txt
the number is 5
the dog's name is Fido

1
বিকল্পের স্ট্রিংয়ের জন্য এটির জন্য অস্থায়ী ফাইল প্রয়োজন, তাই না? অস্থায়ী ফাইল ছাড়া এটি করার কোনও উপায় আছে কি?
ভ্লাদিস্লাভ রাস্ট্রুসনি

@FractalizeR: কিছু সংস্করণ sed একটি আছে -iবিকল্প (জায়গায় সম্পাদন করা ফাইল) যে অনুরূপ Perl বিকল্প। আপনার জন্য র manpage চেক করুন sed
ক্রিস জনসন

@ ফ্র্যাক্টালাইজআর হ্যাঁ, সেড -i ইনলাইন প্রতিস্থাপন করবে। আপনি যদি টিসিএল (অন্য স্ক্রিপ্টিং ভাষা) দিয়ে স্বাচ্ছন্দ্য বোধ করেন তবে এই থ্রেডটি দেখুন: স্ট্যাকওভারফ্লো
হাই ভু

আমি নীচের সেড কমান্ডের মতো একটি সম্পত্তি ফাইলগুলি থেকে প্রতিস্থাপন তৈরি করেছি: সেড-ই / এস / ^ / এস \ / $ {/ জি '-ই' এস / = /} \ // জি '-ই' এস / $ / \ // g 'the.properties> Used.sed
জাপ ডি

@ হাই ভুর কোড একটি সেড প্রোগ্রাম তৈরি করে এবং সেডের -f পতাকা ব্যবহার করে সেই প্রোগ্রামটি পাস করে। যদি আপনি চান, আপনি পরিবর্তে সেড প্রোগ্রামের প্রতিটি লাইন -e পতাকা ব্যবহার করে সেডের মধ্যে প্রেরণ করতে পারতেন। FWIW টেম্পলেট করার জন্য সেড ব্যবহার করার ধারণাটি আমি পছন্দ করি।
অ্যান্ড্রু অলব্রাইট

23

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

$ cat template.txt
variable1 = ${variable1}
variable2 = $variable2
my-ip = \"$(curl -s ifconfig.me)\"

$ echo $variable1
AAA
$ echo $variable2
BBB
$ eval "echo \"$(<template.txt)\"" 2> /dev/null
variable1 = AAA
variable2 = BBB
my-ip = "11.22.33.44"

অবশ্যই এই পদ্ধতিটি যত্ন সহকারে ব্যবহার করা উচিত, যেহেতু ইভাল স্বেচ্ছাসেবক কোড কার্যকর করতে পারে। এটিকে মূল হিসাবে চালানো প্রশ্নটি থেকে অনেক দূরে। টেমপ্লেটের উদ্ধৃতিগুলি এড়াতে হবে, অন্যথায় তারা খাবে eval

এছাড়াও আপনি যদি চান এখানে নথি ব্যবহার করতে পারেন catথেকেecho

$ eval "cat <<< \"$(<template.txt)\"" 2> /dev/null

@ ব্লক একটি সমাধান দিয়েছে যা বাশ উদ্ধৃতি থেকে বেরিয়ে আসা সমস্যাটিকে এড়িয়ে চলে:

$ eval "cat <<EOF
$(<template.txt)
EOF
" 2> /dev/null

সম্পাদনা করুন: সুডো ব্যবহার করে এটি রুট হিসাবে চালানো সম্পর্কে অংশটি সরানো হয়েছে ...

সম্পাদনা: কীভাবে উদ্ধৃতিগুলি রক্ষা করা দরকার সে সম্পর্কে মন্তব্য যুক্ত করা হয়েছে, মিশ্রণের জন্য প্লককের সমাধান যুক্ত করা হয়েছে!


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

আইএমএইচও বাশ-ভিত্তিক টেম্পলেটগুলি উন্মাদনা, যেহেতু আপনার টেমপ্লেটটি কী করছে তা বোঝার জন্য আপনাকে বাশ প্রোগ্রামার হওয়া দরকার! তবে মন্তব্যের জন্য ধন্যবাদ!
মোগসি

@ অ্যালেক্সবি: এই পদ্ধতিটি একক উদ্ধৃতিগুলির মধ্যে পরিবর্তিত হবে , কারণ evalএড echo / catকমান্ডগুলি প্রক্রিয়া করার সময় তারা স্ট্রিং ডিলিমিটারের চেয়ে ঘেরযুক্ত ডাবল-কোটেড স্ট্রিংয়ের ভিতরে কেবল আক্ষরিক অক্ষর ; চেষ্টা eval "echo \"'\$HOME'\""
mklement0

21

আমার কাছে মোগসির মতো ব্যাশ সমাধান রয়েছে তবে ডাবল কোট থেকে বাঁচতে না দেওয়ার জন্য এখানে স্ট্রিংয়ের পরিবর্তে হেরেডোকের সাথে with

eval "cat <<EOF
$(<template.txt)
EOF
" 2> /dev/null

4
এই সমাধানটি টেমপ্লেটে বাশ প্যারামিটার সম্প্রসারণকে সমর্থন করে। আমার প্রিয় হয় পরামিতি প্রয়োজনীয় সঙ্গে ${param:?}এবং পাখির টেক্সট প্রায় ঐচ্ছিক প্যারামিটার। উদাহরণ: ${DELAY:+<delay>$DELAY</delay>}DELAY অপরিজ্ঞাপিত না হয়ে কোনও কিছুর দিকে প্রসারিত হয় এবং <DElay> 17 </delay> যখন DELAY = 17 হয়।
এরিক বলিঞ্জার 21

2
উহু! এবং ইওএফ ডিলিমিটার পিআইডি এর মতো একটি গতিশীল স্ট্রিং ব্যবহার করতে পারে _EOF_$$
এরিক বলিঞ্জার 21

1
@ এমকেলেটমেন্ট ০ নতুন লাইনের পিছনে কাজ করার জন্য একটি বিস্তৃতি যেমন কিছু খালি যেমন খালি ভেরিয়েবল $trailing_newlineব্যবহার করা বা ব্যবহার করা $NL5এবং এটি 5 টি নিউলাইন হিসাবে সম্প্রসারিত হয়েছে তা নিশ্চিত করা।
xebeche

@xebeche: হ্যাঁ, স্থাপন কি আপনি খুব শেষে সুপারিশ ভিতরেtemplate.txt অনুক্রমে কাজ করবে trailing নতুন লাইন সংরক্ষণ করা।
mklement0

1
একটি মার্জিত সমাধান, তবে নোট করুন যে কমান্ড প্রতিস্থাপন ইনপুট ফাইল থেকে কোনও অনুচর নতুনলাইনগুলি কেটে ফেলবে, যদিও এটি সাধারণত কোনও সমস্যা হবে না। আরেকটি প্রান্তের কেস: ব্যবহারের কারণে eval, যদি এটি নিজস্ব লাইনে template.txtথাকে তবে EOFএটি অকাল-কাল-এখানে-ডকটি বন্ধ করে দেবে এবং এইভাবে কমান্ডটি ভঙ্গ করবে। (@ এক্সবেচে টুপিটির টিপ)।
mklement0

18

জানুয়ারী 6, 2017 সম্পাদনা করুন

আমার কনফিগারেশন ফাইলে আমার ডাবল উদ্ধৃতি রাখা দরকার যাতে সেড সাহায্যে ডাবল উদ্ধৃতিগুলি ডাবল পলায়ন করে:

render_template() {
  eval "echo \"$(sed 's/\"/\\\\"/g' $1)\""
}

আমি নতুন লাইনগুলি অনুসরণ করার কথা ভাবতে পারি না, তবে এর মধ্যে ফাঁকা রেখা রাখা হয়।


যদিও এটি একটি পুরানো বিষয়, আইএমও আমি এখানে আরও মার্জিত সমাধান খুঁজে পেয়েছি: http://pempek.net/articles/2013/07/08/bash-sh-as-template-engine/

#!/bin/sh

# render a template configuration file
# expand variables + preserve formatting
render_template() {
  eval "echo \"$(cat $1)\""
}

user="Gregory"
render_template /path/to/template.txt > path/to/configuration_file

গ্রিগরি পাকোসকে সমস্ত ক্রেডিট ।


এটি ইনপুট থেকে ডাবল উদ্ধৃতিগুলি সরিয়ে দেয় এবং, যদি ইনপুট ফাইলে একাধিক ট্রেলিং নিউলাইন থাকে তবে সেগুলিকে একক দিয়ে প্রতিস্থাপন করে।
mklement0

2
এটির কাজটি করার জন্য আমার দুটি কম ব্যাকস্ল্যাশ দরকার ছিল, eval "echo \"$(sed 's/\"/\\"/g' $1)\""
ডেভিড বাউ

দুর্ভাগ্যক্রমে, এই পদ্ধতির আপনাকে পিএইচপি ফাইলগুলিতে টেমপ্লেট করতে দেয় না (সেগুলিতে রয়েছে $variables)।
আইএসআরটিঞ্জার

10

চাকা পুনর্নবীকরণের পরিবর্তে envsubst সঙ্গে যান প্রায় কোনও পরিস্থিতিতে ব্যবহার করা যেতে পারে, উদাহরণস্বরূপ ডকার পাত্রে পরিবেশগত ভেরিয়েবল থেকে কনফিগারেশন ফাইলগুলি তৈরি করা।

যদি ম্যাকটিতে নিশ্চিত হন যে আপনার হোমব্রু হয়েছে তবে এটি gettext থেকে লিঙ্ক করুন:

brew install gettext
brew link --force gettext

./template.cfg

# We put env variables into placeholders here
this_variable_1 = ${SOME_VARIABLE_1}
this_variable_2 = ${SOME_VARIABLE_2}

./.env:

SOME_VARIABLE_1=value_1
SOME_VARIABLE_2=value_2

./configure.sh

#!/bin/bash
cat template.cfg | envsubst > whatever.cfg

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

# make script executable
chmod +x ./configure.sh
# source your variables
. .env
# export your variables
# In practice you may not have to manually export variables 
# if your solution depends on tools that utilise .env file 
# automatically like pipenv etc. 
export SOME_VARIABLE_1 SOME_VARIABLE_2
# Create your config file
./configure.sh

এই অনুরোধ ক্রমটি envsubstআসলে কাজ করে।
অ্যালেক্স

অন্য কেউ খুঁজছেন, জন্য envsubstMacOS এর উপর কাজ না করে, আপনি homebrew ব্যবহার করে এটি ইনস্টল করতে হবে চাই: brew install gettext
ম্যাট

9

গৃহীত উত্তরের দীর্ঘতর তবে আরও শক্তিশালী সংস্করণ:

perl -pe 's;(\\*)(\$([a-zA-Z_][a-zA-Z_0-9]*)|\$\{([a-zA-Z_][a-zA-Z_0-9]*)\})?;substr($1,0,int(length($1)/2)).($2&&length($1)%2?$2:$ENV{$3||$4});eg' template.txt

এটি বা এর সমস্ত দৃষ্টান্ত প্রসারিত করে$VAR ${VAR} তাদের পরিবেশগত মানগুলিতে (বা, তারা যদি পূর্বনির্ধারিত হয় তবে খালি স্ট্রিং)।

এটি সঠিকভাবে ব্যাকস্ল্যাশগুলি থেকে রেহাই পায় এবং একটি ব্যাকস্ল্যাশ-পলায়ন গ্রহণ করে - প্রতিস্থাপনকে বাধা দেয় (এনভাসবুস্টের বিপরীতে যা দেখা যায় যে এটি করে না )।

সুতরাং, যদি আপনার পরিবেশটি হয়:

FOO=bar
BAZ=kenny
TARGET=backslashes
NOPE=engi

এবং আপনার টেম্পলেটটি হ'ল:

Two ${TARGET} walk into a \\$FOO. \\\\
\\\$FOO says, "Delete C:\\Windows\\System32, it's a virus."
$BAZ replies, "\${NOPE}s."

ফলাফলটি হবে:

Two backslashes walk into a \bar. \\
\$FOO says, "Delete C:\Windows\System32, it's a virus."
kenny replies, "${NOPE}s."

যদি আপনি কেবল $ এর আগে ব্যাকস্ল্যাশগুলি থেকে বাঁচতে চান (আপনি কোনও টেম্পলেট অপরিবর্তিতভাবে "সি: \ উইন্ডোজ \ সিস্টেম 32" লিখতে পারেন), এই সামান্য-সংশোধিত সংস্করণটি ব্যবহার করুন:

perl -pe 's;(\\*)(\$([a-zA-Z_][a-zA-Z_0-9]*)|\$\{([a-zA-Z_][a-zA-Z_0-9]*)\});substr($1,0,int(length($1)/2)).(length($1)%2?$2:$ENV{$3||$4});eg' template.txt

8

আমি এটি এইভাবে করতাম, সম্ভবত কম দক্ষ, তবে পড়া / বজায় রাখা সহজ easier

TEMPLATE='/path/to/template.file'
OUTPUT='/path/to/output.file'

while read LINE; do
  echo $LINE |
  sed 's/VARONE/NEWVALA/g' |
  sed 's/VARTWO/NEWVALB/g' |
  sed 's/VARTHR/NEWVALC/g' >> $OUTPUT
done < $TEMPLATE

10
আপনি লাইন-বাই-লাইনটি না পড়ে এবং কেবলমাত্র একটি নিমন্ত্রণের মাধ্যমে এটি করতে পারেন:sed -e 's/VARONE/NEWVALA/g' -e 's/VARTWO/NEWVALB/g' -e 's/VARTHR/NEWVALC/g' < $TEMPLATE > $OUTPUT
ব্র্যান্ডন ব্লুম

8

আপনি যদি জিনজা 2 টেম্পলেটগুলি ব্যবহার করতে চান তবে এই প্রকল্পটি দেখুন: j2cli

এটি সমর্থন করে:

  • JSON, INI, YAML ফাইল এবং ইনপুট স্ট্রিমের টেমপ্লেট
  • পরিবেশের ভেরিয়েবল থেকে টেম্পলেট করা

5

খাঁটি বাশ ব্যবহার করে জাইএক্সের কাছ থেকে উত্তর নেওয়া কিন্তু নতুন স্টাইলের রেগেক্স ম্যাচিং এবং অপ্রত্যক্ষ প্যারামিটার বিকল্পের সাথে এটি হয়ে যায়:

#!/bin/bash
regex='\$\{([a-zA-Z_][a-zA-Z_0-9]*)\}'
while read line; do
    while [[ "$line" =~ $regex ]]; do
        param="${BASH_REMATCH[1]}"
        line=${line//${BASH_REMATCH[0]}/${!param}}
    done
    echo $line
done

5

তাহলে ব্যবহার পার্ল একটি বিকল্প এবং আপনার উপর প্রসারণও ভিত্তিবিন্দু সাথে এসেছেন বিষয়বস্তু পরিবেশ শুধুমাত্র ভেরিয়েবল (হিসাবে সব উল্টোদিকে শেল ভেরিয়েবল), বিবেচনা স্টুয়ার্ট পি বেন্টলি এর শক্তসমর্থ উত্তর

এই উত্তরের উদ্দেশ্য কেবলমাত্র ব্যাশ-কেবল সমাধান সরবরাহ করা - যা ব্যবহার সত্ত্বেও - ব্যবহারে নিরাপদeval হওয়া উচিত ।

গোল আছেন:

  • উভয় সমর্থনযোগ্য ${name}এবং $nameপরিবর্তনশীল উল্লেখ।
  • অন্যান্য সমস্ত বিস্তৃতি রোধ করুন:
    • কমান্ড বিকল্প ( $(...)এবং উত্তরাধিকার বাক্য গঠন `...`)
    • পাটিগণিতের বিকল্পগুলি ( $((...))এবং লিগ্যাসি সিনট্যাক্স $[...])।
  • \(এর সাথে প্রিফিক্স করে ভেরিয়েবল প্রসারণের নির্বাচনী দমনকে মঞ্জুরি দিন\${name} ) এর ।
  • বিশেষ অক্ষর সংরক্ষণ করুন। ইনপুট, উল্লেখযোগ্য "এবং \দৃষ্টান্ত।
  • আর্গুমেন্টের মাধ্যমে বা স্ট্ডিনের মাধ্যমে ইনপুটটিকে মঞ্জুরি দিন।

ফাংশনexpandVars() :

expandVars() {
  local txtToEval=$* txtToEvalEscaped
  # If no arguments were passed, process stdin input.
  (( $# == 0 )) && IFS= read -r -d '' txtToEval
  # Disable command substitutions and arithmetic expansions to prevent execution
  # of arbitrary commands.
  # Note that selectively allowing $((...)) or $[...] to enable arithmetic
  # expressions is NOT safe, because command substitutions could be embedded in them.
  # If you fully trust or control the input, you can remove the `tr` calls below
  IFS= read -r -d '' txtToEvalEscaped < <(printf %s "$txtToEval" | tr '`([' '\1\2\3')
  # Pass the string to `eval`, escaping embedded double quotes first.
  # `printf %s` ensures that the string is printed without interpretation
  # (after processing by by bash).
  # The `tr` command reconverts the previously escaped chars. back to their
  # literal original.
  eval printf %s "\"${txtToEvalEscaped//\"/\\\"}\"" | tr '\1\2\3' '`(['
}

উদাহরণ:

$ expandVars '\$HOME="$HOME"; `date` and $(ls)'
$HOME="/home/jdoe"; `date` and $(ls)  # only $HOME was expanded

$ printf '\$SHELL=${SHELL}, but "$(( 1 \ 2 ))" will not expand' | expandVars
$SHELL=/bin/bash, but "$(( 1 \ 2 ))" will not expand # only ${SHELL} was expanded
  • পারফরম্যান্সের কারণে, ফাংশনটি স্ট্যান্ডিন ইনপুটটি একবারে মেমরির মধ্যে পড়ে, তবে ফাংশনটিকে একটি লাইন বাই লাইন পদ্ধতির সাথে মানিয়ে নেওয়া সহজ।
  • নন-বেসিক ভেরিয়েবল প্রসারকে সমর্থন করে ${HOME:0:10}যেমন যতক্ষণ না তাদের মধ্যে এমবেড থাকা কমান্ড বা পাটিগণিতের বিকল্প থাকে না যেমন${HOME:0:$(echo 10)}
    • এই জাতীয় এম্বেড থাকা বিকল্পগুলি আসলে কার্যটি BREAK করে দেয় (কারণ সমস্ত $(এবং `দৃষ্টান্ত অন্ধভাবে পালিয়ে যায়)।
    • একইভাবে, বিকৃত ভেরিয়েবলের উল্লেখ যেমন ${HOME(নিখোঁজ হওয়া বন্ধ হওয়া }) BREAK ফাংশন।
  • ডাবল-উদ্ধৃত স্ট্রিংগুলিতে বাশের হ্যান্ডলিংয়ের কারণে, ব্যাকস্ল্যাশগুলি নিম্নরূপে পরিচালনা করা হয়:
    • \$name সম্প্রসারণ রোধ করে।
    • একটি \পিছু অনুসরণ করা $হয় না হিসাবে সংরক্ষণ করা হয়।
    • আপনি যদি একাধিক সংলগ্ন \ উদাহরণ উপস্থাপন করতে চান তবে আপনাকে অবশ্যই এগুলি দ্বিগুণ করতে হবে ; উদাহরণ:
      • \\-> \- ঠিক হিসাবে একই\
      • \\\\ -> \\
    • ইনপুট নিম্নলিখিত থাকতে পারবে না (খুব কমই ব্যবহৃত) অক্ষর, যা অভ্যন্তরীণ উদ্দেশ্যে ব্যবহার করা হয়: 0x1, 0x2, 0x3
  • একটি বৃহত কাল্পনিক উদ্বেগ আছে যে যদি বাশ নতুন প্রসারণ সিনট্যাক্স প্রবর্তন করে তবে এই ফাংশনটি এ জাতীয় প্রসারণ রোধ করতে পারে না - এমন একটি সমাধানের জন্য নীচে দেখুন যা ব্যবহার না করে eval

আপনি যদি এমন আরও বিধিনিষেধযুক্ত সমাধান সন্ধান করছেন যা কেবলমাত্র${name} বিস্তারে সমর্থন করে - যেমন রেফারেন্সগুলি উপেক্ষা করে বাধ্যতামূলক কোঁকড়ানো ধনুর্বন্ধনী সহ $name- আমার এই উত্তরটি দেখুন ।


এখানে কেবলমাত্র বাশ-এরeval একটি উন্নত সংস্করণ রয়েছে - গ্রহণযোগ্য উত্তর থেকে বিনামূল্যে সমাধান :

উন্নতিগুলি হ'ল:

  • উভয় ${name}এবং $nameপরিবর্তনশীল রেফারেন্সের সম্প্রসারণের জন্য সমর্থন ।
  • \-স্কেপিং ভেরিয়েবল রেফারেন্সগুলির জন্য সমর্থন যা প্রসারিত করা উচিত নয়।
  • evalউপরোক্ত ভিত্তিক সমাধানের বিপরীতে ,
    • অ-বেসিক বিস্তৃতি উপেক্ষা করা হয়
    • ত্রুটিযুক্ত ভেরিয়েবল উল্লেখগুলি উপেক্ষা করা হয় (তারা স্ক্রিপ্টটি ভঙ্গ করে না)
 IFS= read -d '' -r lines # read all input from stdin at once
 end_offset=${#lines}
 while [[ "${lines:0:end_offset}" =~ (.*)\$(\{([a-zA-Z_][a-zA-Z_0-9]*)\}|([a-zA-Z_][a-zA-Z_0-9]*))(.*) ]] ; do
      pre=${BASH_REMATCH[1]} # everything before the var. reference
      post=${BASH_REMATCH[5]}${lines:end_offset} # everything after
      # extract the var. name; it's in the 3rd capture group, if the name is enclosed in {...}, and the 4th otherwise
      [[ -n ${BASH_REMATCH[3]} ]] && varName=${BASH_REMATCH[3]} || varName=${BASH_REMATCH[4]}
      # Is the var ref. escaped, i.e., prefixed with an odd number of backslashes?
      if [[ $pre =~ \\+$ ]] && (( ${#BASH_REMATCH} % 2 )); then
           : # no change to $lines, leave escaped var. ref. untouched
      else # replace the variable reference with the variable's value using indirect expansion
           lines=${pre}${!varName}${post}
      fi
      end_offset=${#pre}
 done
 printf %s "$lines"

5

এখানে আরও একটি খাঁটি বাশ সমাধান:

  • এটি হেরডোক ব্যবহার করছে, তাই:
    • সংযোজন প্রয়োজনীয় সংশ্লেষের কারণে জটিলতা বৃদ্ধি পায় না
    • টেমপ্লেটে বাশ কোড অন্তর্ভুক্ত থাকতে পারে
      • এটি আপনাকে স্টাফগুলি সঠিকভাবে ইনডেন্ট করতে দেয়। নিচে দেখ.
  • এটি eval ব্যবহার করে না, তাই:
    • খালি লাইনগুলি অনুসরণ করার ক্ষেত্রে কোনও সমস্যা নেই
    • টেমপ্লেটে উদ্ধৃতিগুলির সাথে কোনও সমস্যা নেই

$ cat code

#!/bin/bash
LISTING=$( ls )

cat_template() {
  echo "cat << EOT"
  cat "$1"
  echo EOT
}

cat_template template | LISTING="$LISTING" bash

$ cat template (পিছনের নিউলাইন এবং ডাবল উদ্ধৃতি সহ)

<html>
  <head>
  </head>
  <body> 
    <p>"directory listing"
      <pre>
$( echo "$LISTING" | sed 's/^/        /' )
      <pre>
    </p>
  </body>
</html>

আউটপুট

<html>
  <head>
  </head>
  <body> 
    <p>"directory listing"
      <pre>
        code
        template
      <pre>
    </p>
  </body>
</html>

4

এখানে আরও একটি সমাধান রয়েছে: সমস্ত ভেরিয়েবল এবং টেমপ্লেট ফাইলের বিষয়বস্তু সহ একটি ব্যাশ স্ক্রিপ্ট তৈরি করুন, সেই স্ক্রিপ্টটি দেখতে এই রকম হবে:

word=dog           
i=1                
cat << EOF         
the number is ${i} 
the word is ${word}

EOF                

আমরা যদি এই স্ক্রিপ্টটিকে ব্যাশে ফিড করি তবে এটি পছন্দসই আউটপুট তৈরি করতে পারে:

the number is 1
the word is dog

কীভাবে সেই স্ক্রিপ্টটি তৈরি করা যায় এবং সেই স্ক্রিপ্টটি ব্যাশে ফিড করা যায়:

(
    # Variables
    echo word=dog
    echo i=1

    # add the template
    echo "cat << EOF"
    cat template.txt
    echo EOF
) | bash

আলোচনা

  • প্রথম বন্ধনী একটি সাব শেল খোলে, এর উদ্দেশ্য উত্পন্ন সমস্ত আউটপুট একসাথে ভাগ করে নেওয়া
  • সাব শেলের মধ্যে, আমরা সমস্ত পরিবর্তনশীল ঘোষণা উত্পন্ন করি
  • সাব শেলের catমধ্যেও আমরা HEREDOC দিয়ে কমান্ড তৈরি করি
  • অবশেষে, আমরা সাব শেল আউটপুটকে ব্যাশ করতে এবং পছন্দসই আউটপুট উত্পাদন করি feed
  • আপনি যদি এই আউটপুটটিকে কোনও ফাইলে পুনর্নির্দেশ করতে চান তবে সর্বশেষ লাইনটি এর সাথে প্রতিস্থাপন করুন:

    ) | bash > output.txt


3

Shtpl জন্য উপযুক্ত কেস । (আমার প্রকল্প, সুতরাং এটি ব্যাপকভাবে ব্যবহৃত হয় না এবং ডকুমেন্টেশনের অভাব রয়েছে But তবে এটি যেভাবেই প্রস্তাব দেয় সমাধান এখানে is আপনি এটি পরীক্ষা করতে চান))

শুধু চালানো:

$ i=1 word=dog sh -c "$( shtpl template.txt )"

ফলাফলটি হ'ল:

the number is 1
the word is dog

আনন্দ কর.


1
যদি এটি কৃপণ হয় তবে তা যেকোনভাবেই হ্রাস পেয়েছে। এবং আমি ঠিক আছে। তবে ঠিক আছে, পয়েন্টটি নেওয়া হয়েছে, এটি স্পষ্টভাবে দৃশ্যমান নয়, এটি আসলে আমার প্রকল্প। ভবিষ্যতে এটি আরও দৃশ্যমান করতে যাচ্ছি। আপনার মন্তব্য এবং আপনার সময়ের জন্য যাইহোক ধন্যবাদ।
zstegi

আমি যুক্ত করতে চাই, যে আমি গতকাল সত্যই ইউজক্যাসগুলি অনুসন্ধান করেছি, যেখানে shtpl একটি নিখুঁত সমাধান হবে। হ্যাঁ, আমি বিরক্ত হয়ে
পড়েছিলাম

3
# Usage: template your_file.conf.template > your_file.conf
template() {
        local IFS line
        while IFS=$'\n\r' read -r line ; do
                line=${line//\\/\\\\}         # escape backslashes
                line=${line//\"/\\\"}         # escape "
                line=${line//\`/\\\`}         # escape `
                line=${line//\$/\\\$}         # escape $
                line=${line//\\\${/\${}       # de-escape ${         - allows variable substitution: ${var} ${var:-default_value} etc
                # to allow arithmetic expansion or command substitution uncomment one of following lines:
#               line=${line//\\\$\(/\$\(}     # de-escape $( and $(( - allows $(( 1 + 2 )) or $( command ) - UNSECURE
#               line=${line//\\\$\(\(/\$\(\(} # de-escape $((        - allows $(( 1 + 2 ))
                eval "echo \"${line}\"";
        done < "$1"
}

এটি আপনার পছন্দ অনুসারে সামঞ্জস্যযোগ্য খাঁটি বাশ ফাংশন, উত্পাদনে ব্যবহৃত হয় এবং কোনও ইনপুট ভাঙা উচিত নয়। যদি এটি ভেঙে যায় - আমাকে জানান।


1

আপনি বেসিবল (যা অভ্যন্তরীণভাবে উপরে / নীচে বর্ণিত মূল্যায়ন পদ্ধতির ব্যবহার করে) ব্যবহার করতে পারেন ।

একটি উদাহরণ রয়েছে, কীভাবে একাধিক অংশ থেকে এইচটিএমএল তৈরি করা যায়:

https://github.com/mig1984/bashible/tree/master/examples/templates


0

এখানে একটি বাশ ফাংশন যা হোয়াইটস্পেস সংরক্ষণ করে:

# Render a file in bash, i.e. expand environment variables. Preserves whitespace.
function render_file () {
    while IFS='' read line; do
        eval echo \""${line}"\"
    done < "${1}"
}

0

perlঅন্যান্য কয়েকটি উত্তরের উপর ভিত্তি করে এখানে একটি পরিবর্তিত স্ক্রিপ্ট রয়েছে:

perl -pe 's/([^\\]|^)\$\{([a-zA-Z_][a-zA-Z_0-9]*)\}/$1.$ENV{$2}/eg' -i template

বৈশিষ্ট্যগুলি (আমার প্রয়োজনের ভিত্তিতে, তবে সংশোধন করা সহজ হওয়া উচিত):

  • স্কিপগুলি প্যারামিটারের বিস্তৃতি থেকে রক্ষা পেয়েছে (যেমন \ $ {VAR})।
  • Form {VAR the ফর্মের প্যারামিটার বিস্তৃতি সমর্থন করে, তবে $ VAR নয়।
  • যদি ভিএআর এনভর না থাকে তবে ফাঁকা স্ট্রিংয়ের সাথে a {VAR} প্রতিস্থাপন করে।
  • শুধুমাত্র অ্যাজ, এজেড, 0-9 এবং নামের আন্ডারস্কোর অক্ষরকে সমর্থন করে (প্রথম অবস্থানে অঙ্কগুলি বাদ দিয়ে)।

0

সরল ভেরিয়েবল সাবস্টিটিউশন পাইথন স্ক্রিপ্টটি এখানে দেখুন: https://github.com/jeckep/vsubst

এটা ব্যবহার করা খুবই সহজ:

python subst.py --props secure.properties --src_path ./templates --dst_path ./dist

0

এই দুর্দান্ত প্রশ্নে আমার বিনীত অবদান।

tpl() {
    local file=$(cat - | \
                 sed -e 's/\"/\\"/g' \
                     -e "s/'/\\'/g")
    local vars=$(echo ${@} | tr ' ' ';')
    echo "$(sh -c "${vars};echo \"$file\"")"
}

cat tpl.txt | tpl "one=fish" "two=fish"

এটি মূলত এনভের রিপ্লেসমেন্টটি করতে সাবসেল ব্যবহার করে কাজ করে কেবল এটি ইওাল ব্যবহার করে না এবং এটি একক এবং ডাবল উদ্ধৃতিগুলি স্পষ্টভাবে পালিয়ে যায়। এটা তোলে গুলান না করার কোন শূণ্যস্থান সঙ্গে একটি একক লাইন মধ্যে Var এক্সপ্রেশন concatenates shএবং তারপর টেমপ্লেট পাসের echo, লেট shহ্যান্ডেল Var প্রতিস্থাপন। এটি নিউলাইন, মন্তব্য ইত্যাদি সংরক্ষণ করে ... এবং \${like_this}যদি আপনি বর্ণটি ব্যাখ্যা না করতে চান তবে আপনি পালাতে পারবেন ।${missing_var}খালি মান দিয়ে প্রতিস্থাপন করা হবে।

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

উপভোগ করুন!


0

এই পৃষ্ঠায় প্লককের উত্তর অনুসরণ করতে, আপনারা যারা বাশিজম এড়ানোর জন্য সন্ধান করছেন তাদের জন্য এখানে একটি ড্যাশ-উপযুক্ত সংস্করণ is

eval "cat <<EOF >outputfile
$( cat template.in )
EOF
" 2> /dev/null

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