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


163

আমি একটি "টেম্পলেট" ফাইলের আউটপুটটি মাইএসকিউএল এ পাইপ করতে চাই, ফাইলটি ${dbName}ছেদ করার মতো ভেরিয়েবল রয়েছে । এই দৃষ্টান্তগুলি প্রতিস্থাপন করতে এবং আউটপুটটিকে স্ট্যান্ডার্ড আউটপুটে ডাম্প করতে কমান্ড লাইন ইউটিলিটিটি কী?

উত্তর:


192

শেড !

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

সংখ্যাটি $ {i is
শব্দটি $ $ শব্দ}

আমাদের শুধু বলতে হবে:

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

জোনাথন লেফলারকে -eএকই sedঅনুরোধে একাধিক যুক্তি দেওয়ার জন্য টিপ দেওয়ার জন্য ধন্যবাদ ।


13
আপনি এই দুটি সেড কমান্ডকে এক সাথে একত্রিত করতে পারেন: সেড -e "এস / \ $ {{আই} / 1 /" -e "এস / \ $ {শব্দ} / কুকুর /"; যে আরও দক্ষ। আপনি এ জাতীয় 100 টি ক্রিয়াকলাপে সেডের কয়েকটি সংস্করণ নিয়ে সমস্যা তৈরি করতে পারেন (বছর আগের সমস্যা - এখনও সত্য নাও হতে পারে, তবে এইচপি-ইউএক্স থেকে সাবধান থাকুন)।
জোনাথন লেফলার

1
ধন্যবাদ জোনাথন, ঠিক আমি যা খুঁজছিলাম
দানা দ্য সনে

3
ছোট ইঙ্গিত: যদি প্রদত্ত উদাহরণে "1" বা "কুকুর" একটি ডলারের প্রতীক ধারণ করে, আপনি এটি একটি ব্যাকস্ল্যাশ দিয়ে পালাতে হবে (অন্যথায় প্রতিস্থাপনটি ঘটে না)।
ম্যাথিউইপি

9
এছাড়াও আপনি প্রয়োজন হবে না cat। আপনার যা দরকার তা হল sed -e "s/\${i}/1/" -e "s/\${word}/dog/" template.text
হার্ডলিঙ্কনিউম

3
প্রতিস্থাপন পাঠ্য যদি একটি পাসওয়ার্ড হয়? এই ক্ষেত্রে, sedএকটি পালিয়ে আসা পাঠ্য প্রত্যাশা করবে, যা একটি ঝামেলা।
jpbochi

177

হালনাগাদ

এই একই প্রশ্নে ইয়োটটাসার একটি সমাধান রয়েছে যা কেবলমাত্র $ VAR বা $ {VAR like এর মতো পরিবর্তকের জন্য প্রতিস্থাপন করে এবং সংক্ষিপ্ত ওয়ান-লাইনার er

i=32 word=foo envsubst < template.txt

অবশ্যই যদি আমি এবং শব্দটি আপনার পরিবেশে থাকে তবে এটি ঠিক

envsubst < template.txt

আমার ম্যাক এটা দেখে মনে হচ্ছে এটা অংশ হিসাবে ইনস্টল করা ছিল gettext এর থেকে MacGPG2

পুরানো উত্তর

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

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

এই দুটি সমাধান শক্তি আপনি শুধুমাত্র স্বাভাবিকভাবে $ ((...)) যে ঘটবে না কয়েক শেল প্রসারণও ধরনের, `...` পেতে, এবং $ (...), যদিও ব্যাকস্ল্যাশ হয় একটি চরিত্রটি এখানে রক্ষা করুন, তবে আপনাকে ভাবতে হবে না যে পার্সিংয়ে একটি ত্রুটি রয়েছে এবং এটি একাধিক লাইন ঠিক জরিমানা করে।


6
আমি খালি খুঁজে envsubstপেয়েছি যদি আপনার এনভার্স রফতানি না হয় তবে কাজ করে না।
টোডিয়াস ঝো

4
@ টোডিয়াসজহো: পরিবেশগত পরিবর্তনশীল হিসাবে এমন কোনও জিনিস নেই যা রফতানি হয় না - এটি অবশ্যই রফতানি হয় যা শেল ভেরিয়েবলকে পরিবেশগত পরিবর্তনশীল করে তোলে । envsubst, এর নাম অনুসারে, কেবল পরিবেশের ভেরিয়েবলগুলি সনাক্ত করে , শেল ভেরিয়েবলগুলি নয়। এটি envsubstএকটি জিএনইউ ইউটিলিটি, এবং অতএব ইনস্টল করা বা সমস্ত প্ল্যাটফর্মগুলিতে উপলব্ধ নয় তা লক্ষণীয় ।
mklement0

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

1
আমার এতে একটি স্ট্রিং রয়েছে it এর মধ্যে হোম, আমি খুঁজে পেয়েছি default হোমটি করণীয় হিসাবে ডিফল্ট শেল হিসাবে কাজ করা হয়েছে, তার পরিবর্তে $ হোমকে আমার নিজের / বাড়ি / zw963 হিসাবে ব্যবহার করা হবে, তবে, এটি $ (বিড়াল / ইত্যাদি / হোস্টনাম) বিকল্পটি সমর্থন করে না বলে মনে হয়, সুতরাং এটি আমার নিজের চাহিদা মেলে না।
zw963

3
"ওল্ড উত্তর" এর জন্য ধন্যবাদ, কারণ এটি কেবল চলকগুলিকেই অনুমতি দেয় না, তবে $ (ls -l) এর মতো শেল
আলেক

46

ব্যবহার /bin/sh। একটি ছোট শেল স্ক্রিপ্ট তৈরি করুন যা ভেরিয়েবলগুলি সেট করে এবং তারপরে শেলটি নিজেই ব্যবহার করে টেম্পলেটটি পার্স করে। পছন্দ করুন (সঠিকভাবে নিউলাইনগুলি হ্যান্ডেল করতে সম্পাদনা করুন):

ফাইল টেমপ্লেট টেক্সট:

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

ফাইল স্ক্রিপ্ট.শ:

#!/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"

আউটপুট:

#sh script.sh
the number is 1
the word is dog

2
কেন শুধু নয়: পড়ার লাইনে; do eval প্রতিধ্বনি "$ লাইন"; সম্পন্ন হয়েছে <./template.txt ??? পুরো ফাইলটি মেমরিতে পড়ার দরকার নেই, কেবল মাথা এবং লেজের নিবিড় ব্যবহারের মাধ্যমে এটি একবারে এক লাইন ছিটকে দিতে। তবে 'ইভাল' ঠিক আছে - যদি না টেমপ্লেটে ব্যাক কোটের মতো শেল অক্ষর থাকে।
জোনাথন লেফলার

16
এটা খুব বিপজ্জনক! bashইনপুট সমস্ত কমান্ড কার্যকর করা হবে। যদি টেমপ্লেটটি হয়: "শব্দগুলি হল; আরএম -আরএফ OME হোম" আপনি ফাইলগুলি আলগা করুন।
rzymek

1
@ আরজিমেক - মনে রাখবেন, তিনি এই ফাইলটি সরাসরি ডাটাবেসে পাইপ করতে চান। সুতরাং উপস্থিতভাবে, ইনপুটটি বিশ্বাসযোগ্য।
gnud

4
@gnud ফাইলের বিষয়বস্তু সংরক্ষণ করার জন্য পর্যাপ্ত পরিমাণে বিশ্বাস করা এবং এতে থাকা কোনও কিছু কার্যকর করার জন্য পর্যাপ্ত পরিমাণে বিশ্বাসের মধ্যে পার্থক্য রয়েছে।
চিহ্নিত করুন

3
প্রতিবন্ধকতাগুলি লক্ষ করুন: (ক) ইনপুটটিতে ডাবল উদ্ধৃতিগুলি নিঃশব্দে বাতিল করা হয়েছে, (খ) readলিখিতভাবে কমান্ডটি প্রতিটি লাইন এবং 'ইটস' \ অক্ষর থেকে শীর্ষস্থানীয় এবং পিছনের সাদা অংশকে ছাঁটাচ্ছে , ইনপুটকে বিশ্বাস বা নিয়ন্ত্রণ করুন, কারণ ইনপুটটিতে এম্বেড করা কমান্ড বিকল্পগুলি ( `…` বা $(…)) ব্যবহারের কারণে স্বেচ্ছাসেবক কমান্ড কার্যকর করতে দেয় eval। শেষ অবধি, একটি ছোট্ট সুযোগ রয়েছে যে echoএর একটি কমান্ড-লাইন বিকল্পের জন্য একটি লাইনের সূচনা ভুল করে।
এমকেলেটিনে

23

সাম্প্রতিক আগ্রহের ভিত্তিতে আমি আবার এটি নিয়ে ভাবছিলাম এবং আমি মনে করি যে আমি যে সরঞ্জামটি মূলত ভাবছিলাম তা ছিল m4অটোটুলগুলির ম্যাক্রো প্রসেসর। সুতরাং আমি প্রথমে যে পরিবর্তনশীলটি নির্দিষ্ট করেছিলাম তার পরিবর্তে আপনি ব্যবহার করতে পারেন:

$echo 'I am a DBNAME' | m4 -DDBNAME="database name"

1
এই সমাধানটির এখানে উত্তরগুলির কয়েকটি স্বল্পতা রয়েছে। আপনি কি কেবলমাত্র DBNAME এর পরিবর্তে $ {DBNAME replace প্রতিস্থাপনের কোনও উপায় সম্পর্কে জানেন?
জ্যাক ডেভিডসন

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

13

template.txt

Variable 1 value: ${var1}
Variable 2 value: ${var2}

data.sh

#!/usr/bin/env bash
declare var1="value 1"
declare var2="value 2"

parser.sh

#!/usr/bin/env bash

# args
declare file_data=$1
declare file_input=$2
declare file_output=$3

source $file_data
eval "echo \"$(< $file_input)\"" > $file_output

./parser.sh data.sh টেমপ্লেট। টেক্সট parsed_file.txt

parsed_file.txt

Variable 1 value: value 1
Variable 2 value: value 2

1
অন্য কোথাও উল্লেখ করা হয়েছে: কেবলমাত্র এটি ব্যবহার করুন যদি আপনি সম্পূর্ণভাবে ইনপুটকে বিশ্বাস করেন বা নিয়ন্ত্রণ করেন, কারণ ইনপুটটিতে এম্বেড থাকা কমান্ড বিকল্পগুলি ( `…` বা $(…)) ব্যবহারের কারণে স্বেচ্ছাসেবী আদেশগুলি কার্যকর করতে দেয় এবং ব্যবহারের evalফলে শেল কোডটি সরাসরি প্রয়োগ করে source। এছাড়াও, ইনপুটটিতে ডাবল উদ্ধৃতিগুলি নিঃশব্দে বাতিল করা হয়েছে, এবং echoএর একটি কমান্ড-লাইন বিকল্পের জন্য একটি লাইনের প্রারম্ভিক ভুল করতে পারে।
mklement0

দুর্ভাগ্যক্রমে, এই ফলাফল ফাইলটি থেকে সমস্ত ডাবল উদ্ধৃতি (")
কেটে

আমি এখানে যা খুঁজছিলাম তা পেয়েছি: stackoverflow.com/a/11050943/795158 ; আমি envsubst ব্যবহার। পার্থক্যটি হ'ল ভারগুলি রফতানি করতে হবে যা আমার সাথে ঠিক ছিল।
Ivaylo স্লাভভ

যদি পাঠ্য ফাইলটিতে "` "বা" থাকে। " , সাবস্টিটিউট ব্যর্থ হবে।
শুইখিয়াং

12

এখানে একটি শক্তিশালী বাশ ফাংশন যা ব্যবহার করা সত্ত্বেও eval- ব্যবহারে নিরাপদ হওয়া উচিত।

${varName}ইনপুট পাঠ্যের সমস্ত পরিবর্তনীয় উল্লেখগুলি কলিং শেলের ভেরিয়েবলের ভিত্তিতে প্রসারিত হয়।

অন্য কিছুই প্রসারিত হয়: তন্ন তন্ন পরিবর্তনশীল রেফারেন্স যার নাম না মধ্যে লেখা {...}(যেমন $varName), বা কমান্ড বদল ( $(...)এবং উত্তরাধিকার সিনট্যাক্স `...`), বা গাণিতিক বদল ( $((...))এবং উত্তরাধিকার সিনট্যাক্স $[...])।

$একটি আক্ষরিক হিসাবে চিকিত্সা , \এটি পরীক্ষা; উদাহরণ:\${HOME}

নোট করুন যে ইনপুট কেবল স্টিডিনের মাধ্যমে গৃহীত হবে ।

উদাহরণ:

$ expandVarsStrict <<<'$HOME is "${HOME}"; `date` and \$(ls)' # only ${HOME} is expanded
$HOME is "/Users/jdoe"; `date` and $(ls)

ফাংশন উত্স কোড:

expandVarsStrict(){
  local line lineEscaped
  while IFS= read -r line || [[ -n $line ]]; do  # the `||` clause ensures that the last line is read even if it doesn't end with \n
    # Escape ALL chars. that could trigger an expansion..
    IFS= read -r -d '' lineEscaped < <(printf %s "$line" | tr '`([$' '\1\2\3\4')
    # ... then selectively reenable ${ references
    lineEscaped=${lineEscaped//$'\4'{/\${}
    # Finally, escape embedded double quotes to preserve them.
    lineEscaped=${lineEscaped//\"/\\\"}
    eval "printf '%s\n' \"$lineEscaped\"" | tr '\1\2\3\4' '`([$'
  done
}

ফাংশন ধরে নেয় যে কোন 0x1, 0x2, 0x3, এবং 0x4নিয়ন্ত্রণ অক্ষর ইনপুট উপস্থিত, কারণ ঐ অক্ষর। অভ্যন্তরীণভাবে ব্যবহৃত হয় - যেহেতু ফাংশনটি পাঠ্য প্রক্রিয়া করে , এটি একটি নিরাপদ অনুমান হওয়া উচিত।


2
এটি এখানে সেরা উত্তর এক। এমনকি evalএটি ব্যবহার করে ব্যবহার করা বেশ নিরাপদ।
অনুভা

1
এই সমাধানটি JSON ফাইলগুলির সাথে কাজ করে! ( "সঠিকভাবে পালানো !)
ডাব্লুবিআর

2
এই সমাধানটির সাথে একটি দুর্দান্ত জিনিস হ'ল এটি আপনাকে ভেরিয়েবলগুলি হারিয়ে যাওয়ার জন্য ডিফল্ট সরবরাহ করতে দেয় ${FOO:-bar}বা সেট করা থাকলে কেবল কোনও আউটপুট দেয় - ${HOME+Home is ${HOME}}। আমি সন্দেহ করি যে এটি একটি সামান্য এক্সটেনশনের সাথেও হারিয়ে যাচ্ছে ভেরিয়েবলগুলির জন্য প্রস্থান কোডগুলি ফেরত দিতে পারে ${FOO?Foo is missing}তবে বর্তমানে tldp.org/LDP/abs/html/parameter-substedia.html এর একটি তালিকা রয়েছে যদি এটি সাহায্য করে
স্টুয়ার্ট মুর

11

তৈরি করুন rendertemplate.sh:

#!/usr/bin/env bash

eval "echo \"$(cat $1)\""

এবং template.tmpl:

Hello, ${WORLD}
Goodbye, ${CHEESE}

টেমপ্লেটটি রেন্ডার করুন:

$ export WORLD=Foo
$ CHEESE=Bar ./rendertemplate.sh template.tmpl 
Hello, Foo
Goodbye, Bar

2
এই স্ট্রিপগুলি ডাবল উদ্ধৃত স্ট্রিংগুলি বন্ধ করে দেয়
vrtx54234

চেষ্টা করেছেন: ইভাল "প্রতিধ্বনি $ (বিড়াল $ 1)" - ডাব্লু / আউট উদ্ধৃতি, এবং এটি আমার পক্ষে কাজ করেছে।
অ্যাক্সেস_গ্রেঞ্জড

2
সুরক্ষা দৃষ্টিকোণ থেকে, এটি একটি খারাপ খবর। যদি আপনার টেম্পলেটটি থাকে তবে $(rm -rf ~)আপনি কোড হিসাবে এটি চালাচ্ছেন।
চার্লস ডাফি

eval "echo \"$(cat $1)\"" দুর্দান্ত কাজ!
দেব দেব

10

প্রাক্তন উত্তরের ভিত্তিতে পার্লের সাথে আমার সমাধানটি এখানে পরিবেশের ভেরিয়েবলগুলি প্রতিস্থাপন করে:

perl -p -e 's/\$\{(\w+)\}/(exists $ENV{$1}?$ENV{$1}:"missing variable $1")/eg' < infile > outfile

2
এটা অসাধারণ. সর্বদা পার্ল থাকবেন না, তবে আপনি যখন করবেন তখন এটি সহজ এবং সোজা সামনে।
অ্যারন ম্যাকমিলিন

5

আপনি যদি পার্ল ব্যবহারের জন্য উন্মুক্ত হন তবে তা আমার পরামর্শ হবে। যদিও সম্ভবত কিছু সেড এবং / বা এডাব্লুকে বিশেষজ্ঞ রয়েছে যা সম্ভবত এটি কীভাবে আরও সহজভাবে করতে হয় তা জানেন। যদি আপনার প্রতিস্থাপনের জন্য কেবলমাত্র dbName এর চেয়ে আরও জটিল ম্যাপিং থাকে তবে আপনি এটি খুব সহজেই প্রসারিত করতে পারেন, তবে আপনি ঠিক সেই সময়ে এটি একটি স্ট্যান্ডার্ড পার্ল স্ক্রিপ্টে রেখে দিতে পারেন।

perl -p -e 's/\$\{dbName\}/testdb/s' yourfile | mysql

কিছুটা আরও জটিল কিছু করার জন্য একটি ছোট পার্ল স্ক্রিপ্ট (একাধিক কী হ্যান্ডেল করুন):

#!/usr/bin/env perl
my %replace = ( 'dbName' => 'testdb', 'somethingElse' => 'fooBar' );
undef $/;
my $buf = <STDIN>;
$buf =~ s/\$\{$_\}/$replace{$_}/g for keys %replace;
print $buf;

আপনি যদি উপরের স্ক্রিপ্টটির নাম প্রতিস্থাপন-স্ক্রিপ্ট হিসাবে রাখেন, তবে এটি নিম্নলিখিত হিসাবে ব্যবহৃত হতে পারে:

replace-script < yourfile | mysql

1
একক ভেরিয়েবলের জন্য কাজ করে তবে আমি অন্যদের জন্য কীভাবে 'বা' অন্তর্ভুক্ত করব?
দানা দ্য সনে

2
পার্লের সাহায্যে আপনি এটি করতে পারেন এমন অনেকগুলি উপায় রয়েছে, যা আপনি এটি করতে চেয়েছিলেন তা কতটা জটিল এবং / বা সুরক্ষিত তার উপর নির্ভর করে। আরও জটিল উদাহরণগুলি এখানে পাওয়া যাবে: perlmonks.org/?node_id=718936
বিউ সিমেনসেন

3
পার্ল ব্যবহার করা শেলটি ব্যবহারের চেষ্টা করার চেয়ে অনেক বেশি পরিষ্কার। উল্লিখিত শেল-ভিত্তিক সমাধানগুলির মধ্যে কয়েকটি চেষ্টা করার চেয়ে এই কাজটি করার জন্য সময় ব্যয় করুন।
jdigital

1
সম্প্রতি একই ধরণের সমস্যা মোকাবেলা করতে হয়েছিল। শেষ পর্যন্ত আমি পার্লের সাথে গেলাম (এনভসুবস্ট কিছুটা আশাব্যঞ্জক লাগছিল, তবে এটি নিয়ন্ত্রণ করা খুব কঠিন ছিল)।
স্যুট করে

5

আপনার জন্য বিকল্পটি নেওয়ার শেলটি এখানে পাওয়ার একটি উপায়, যেন ফাইলের বিষয়বস্তু পরিবর্তে ডাবল কোটের মধ্যে টাইপ করা থাকে।

বিষয়বস্তু সহ টেমপ্লেট.টেক্সটের উদাহরণ ব্যবহার করে:

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

নিম্নলিখিত লাইনটি শেলটিকে টেমপ্লেট.টিএসটিএসটির বিষয়বস্তুগুলিকে বিভক্ত করবে এবং ফলাফলটি স্ট্যান্ডার্ড আউট থেকে লিখবে।

i='1' word='dog' sh -c 'echo "'"$(cat template.txt)"'"'

ব্যাখ্যা:

  • iএবং wordগৃহীত হয় এনভায়রনমেন্ট ভেরিয়েবল এর মৃত্যুদন্ড থেকে scopped sh
  • sh স্ট্রিংয়ের মধ্যবর্তী বিষয়গুলি কার্যকর করা হয়।
  • একে অপরের পাশে লেখা স্ট্রিংগুলি একটি স্ট্রিং হয়ে যায়, সেই স্ট্রিংটি হ'ল:
    • ' echo "' + " $(cat template.txt)" + ' "'
  • প্রতিস্থাপনের মধ্যে যেহেতু "" $(cat template.txt)" এর আউটপুট হয়ে যায় cat template.txt
  • সুতরাং আদেশ দ্বারা কার্যকর করা sh -cহয়:
    • echo "The number is ${i}\nThe word is ${word}",
    • যেখানে iএবং wordনির্দিষ্ট পরিবেশের পরিবর্তনশীল।

সুরক্ষা দৃষ্টিকোণ থেকে, এটি একটি খারাপ খবর। যদি আপনার টেম্পলেটটিতে থাকে, বলুন, '$(rm -rf ~)'$(rm -rf ~)টেমপ্লেট ফাইলে আক্ষরিক উক্তিগুলি এর প্রসারণের পূর্বে আপনার যুক্ত হওয়াগুলির সাথে মিলবে।
চার্লস ডাফি

আমি ইন-টেম্পলেট কোটগুলি আউট-টেম্পলেট উদ্ধৃতিগুলির সাথে মেলে না, আমি বিশ্বাস করি যে শেলটি টেম্পলেট এবং ইন-টার্মিনাল স্ট্রিংটি স্বতন্ত্রভাবে সমাধান করছে (কোটগুলি অপসারণ কার্যকর) তারপরে সেগুলি সংযুক্ত করে তুলবে aten পরীক্ষার এমন একটি সংস্করণ যা আপনার হোম ডিরেক্টরি মুছবে না '$(echo a)'$(echo a)। এটি উত্পাদন করে 'a'a। প্রধান জিনিস যে ঘটছে তা প্রথমতঃ echo aভিতরে 'মূল্যায়ন হচ্ছে, যা নাও হতে পারে আপনি কি আশা যেহেতু এটি আছে ', কিন্তু সহ হিসাবে একই আচরণ 'মধ্যে "উদ্ধৃত পংক্তি।
এপ্রিওরি

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

বিষয়টি কি? আমি কেবল তাদেরকেই ${varname}নয়, উচ্চ-সুরক্ষা-ঝুঁকি বিস্তারের জন্য জিজ্ঞাসা করতে দেখছি ।
চার্লস ডাফি

... যা বলেছিল, আমার অবশ্যই পৃথক হতে হবে (পুনরায়: ইন-টেম্পলেট এবং আউট-টেম্পলেট উদ্ধৃতিগুলি মিলতে সক্ষম হবে)। আপনি যখন আপনার স্ট্রিংয়ে একটি একক-উদ্ধৃতি রাখেন, আপনি একটি একক-উদ্ধৃত স্ট্রিংয়ে বিভক্ত হন echo ", তার পরে ডাবল-উদ্ধৃত স্ট্রিং এর আক্ষরিক অনুভূতিগুলির পরে template.txt, অন্য শাব্দিক স্ট্রিং দ্বারা অনুসরণ করা হয় ", সমস্ত একক যুক্তিতে পরিণত হয় sh -c। আপনি ঠিক যে করছি 'মিলেছে করা যাবে না (যেহেতু এটি বাইরের শেল ভেতরের এক পাশ বদলে দ্বারা ক্ষয়প্রাপ্ত হয়), কিন্তু "অবশ্যই, তাই একটি টেমপ্লেট ধারণকারী করতে Gotcha"; rm -rf ~; echo "মৃত্যুদন্ড কার্যকর করা যেতে পারে।
চার্লস ডাফি

4

file.tpl:

The following bash function should only replace ${var1} syntax and ignore 
other shell special chars such as `backticks` or $var2 or "double quotes". 
If I have missed anything - let me know.

script.sh:

template(){
    # usage: template file.tpl
    while read -r line ; do
            line=${line//\"/\\\"}
            line=${line//\`/\\\`}
            line=${line//\$/\\\$}
            line=${line//\\\${/\${}
            eval "echo \"$line\""; 
    done < ${1}
}

var1="*replaced*"
var2="*not replaced*"

template file.tpl > result.txt

2
এটি নিরাপদ নয় যেহেতু এটি টেমপ্লেটে কমান্ডের বিকল্পগুলি কার্যকর করবে যদি তাদের অগ্রণী ব্যাকস্ল্যাশ থাকে যেমন\$(date)
পিটার ডলবার্গ

1
পিটারের বৈধ পয়েন্টটি বাদ দিয়ে: আমি আপনাকে কমান্ড while IFS= read -r line; doহিসাবে ব্যবহার করার পরামর্শ দিই read, অন্যথায় আপনি প্রতিটি ইনপুট লাইন থেকে শীর্ষস্থানীয় এবং পিছনের সাদা অংশটি ছাঁটাবেন। এছাড়াও, echoএর একটি কমান্ড-লাইন বিকল্পের জন্য একটি লাইনের সূচনা ভুল করতে পারে, তাই এটি ব্যবহার করা ভাল printf '%s\n'। শেষ পর্যন্ত, এটি ডাবল-উদ্ধৃতিতে নিরাপদ ${1}
mklement0

4

আমি সিগিলের মতো কিছু ব্যবহার করার পরামর্শ দেব : https://github.com/gliderlabs/sigil

এটি একটি একক বাইনারি সংকলিত, সুতরাং এটি সিস্টেমে ইনস্টল করা অত্যন্ত সহজ।

তারপরে আপনি নীচের মতো একটি সাধারণ ওয়ান-লাইনার করতে পারেন:

cat my-file.conf.template | sigil -p $(env) > my-file.conf

এটি evalরেজেকেক্স বা ব্যবহারের চেয়ে অনেক বেশি নিরাপদ এবং সহজsed


2
দুর্দান্ত উত্তর! এটি একটি যথাযথ টেম্প্লেটিং সিস্টেম এবং অন্যান্য উত্তরের তুলনায় কাজ করা আরও সহজ।
এরফান

বিটিডাব্লু, পরিবর্তে এড়ানো catএবং ব্যবহার <my-file.conf.templateকরা আরও ভাল যাতে আপনি sigilকোনও ফিফোর পরিবর্তে একটি আসল ফাইল হ্যান্ডেল দেন।
চার্লস ডাফি

2

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

$ echo $MYTEST
pass!
$ cat FILE
hello $MYTEST world
$ eval echo `cat FILE`
hello pass! world

4
একটি ব্যাশ সাধারণভাবে সংক্ষেপে জন্য $(cat file)হয়$(< file)
গ্লেন জ্যাকম্যান

3
স্পষ্টতই এই পদ্ধতিটি লাইন বিরতির সাথে জগাখিচু হয়ে যায়, অর্থাৎ আমার ফাইলটি সমস্ত এক লাইনে প্রতিধ্বনিত হয়েছিল।
আর্থার কোরেঞ্জান

@ আর্থার কোরেঞ্জান: সত্যই, লাইন ব্রেকগুলি স্থানগুলির সাথে প্রতিস্থাপন করা হয়েছে। এটি ঠিক করার জন্য, আপনাকে ব্যবহার করতে হবে eval echo "\"$(cat FILE)\""তবে ইনপুটটিতে ডাবল উদ্ধৃতিগুলি ফেলে দেওয়া হবে এমনটি এখনও কম হতে পারে।
mklement0

অন্য কোথাও উল্লেখ করা হয়েছে: কেবলমাত্র এটি ব্যবহার করুন যদি আপনি সম্পূর্ণরূপে ইনপুটকে বিশ্বাস করেন বা নিয়ন্ত্রণ করেন, কারণ ইনপুটটিতে এম্বেড থাকা কমান্ড বিকল্পগুলি ( `…` বা $(…)) ব্যবহারের কারণে স্বেচ্ছাচারিত আদেশগুলি কার্যকর করতে দেয় eval
mklement0

2

এখানে প্রচুর পছন্দসই, তবে আমি বুঝতে পেরেছি যে আমি গাদা আমার উপর টাসছি। এটি পার্ল ভিত্তিক, কেবল $ {... form ফর্মের ভেরিয়েবলগুলিকে লক্ষ্য করে, ফাইলটিকে একটি আর্গুমেন্ট হিসাবে প্রক্রিয়া করতে নেয় এবং রূপান্তরিত ফাইলকে স্টাডআউটে আউটপুট দেয়:

use Env;
Env::import();

while(<>) { $_ =~ s/(\${\w+})/$1/eeg; $text .= $_; }

print "$text";

অবশ্যই আমি সত্যিই একজন পারল ব্যক্তি নই, সুতরাং সহজেই মারাত্মক ত্রুটি হতে পারে (যদিও এটি আমার পক্ষে কাজ করে)।


1
ঠিকভাবে কাজ করে. আপনি Env::import();লাইনটি ফেলে দিতে পারেন - আমদানি দ্বারা বোঝানো হয় use। এছাড়াও, আমি প্রথমে স্মৃতিতে পুরো আউটপুট তৈরি না করার পরামর্শ দিই: কেবল লুপের অভ্যন্তরের print;পরিবর্তে ব্যবহার করুন $text .= $_;এবং পোস্ট-লুপ printকমান্ডটি ড্রপ করুন ।
mklement0

1

কনফিগারেশন ফাইল ফর্ম্যাটের আপনার নিয়ন্ত্রণ থাকলে এটি ব্যাশ নিজেই করা যায়। আপনার কনফিগারেশন ফাইলটি সাবস্কেল না করে কেবল ("।") উত্সের প্রয়োজন। এটি নিশ্চিত করে যে ভেরিয়েবলগুলি বর্তমান শেলটির প্রসঙ্গে তৈরি করা হয়েছে (এবং বিদ্যমান থাকা অব্যাহত থাকবে) পরিবর্তে সাব-শেল (যেখানে ভেরিয়েবল অদৃশ্য হয়ে যায় যখন সাব-শেল প্রস্থান করে)।

$ cat config.data
    export parm_jdbc=jdbc:db2://box7.co.uk:5000/INSTA
    export parm_user=pax
    export parm_pwd=never_you_mind

$ cat go.bash
    . config.data
    echo "JDBC string is " $parm_jdbc
    echo "Username is    " $parm_user
    echo "Password is    " $parm_pwd

$ bash go.bash
    JDBC string is  jdbc:db2://box7.co.uk:5000/INSTA
    Username is     pax
    Password is     never_you_mind

যদি আপনার কনফিগারেশন ফাইলটি শেল স্ক্রিপ্ট নাও হতে পারে তবে আপনি এটি সম্পাদন করার আগে এটি কেবল 'সংকলন' করতে পারেন (সংকলনটি আপনার ইনপুট ফর্ম্যাটের উপর নির্ভর করে)।

$ cat config.data
    parm_jdbc=jdbc:db2://box7.co.uk:5000/INSTA # JDBC URL
    parm_user=pax                              # user name
    parm_pwd=never_you_mind                    # password

$ cat go.bash
    cat config.data
        | sed 's/#.*$//'
        | sed 's/[ \t]*$//'
        | sed 's/^[ \t]*//'
        | grep -v '^$'
        | sed 's/^/export '
        >config.data-compiled
    . config.data-compiled
    echo "JDBC string is " $parm_jdbc
    echo "Username is    " $parm_user
    echo "Password is    " $parm_pwd

$ bash go.bash
    JDBC string is  jdbc:db2://box7.co.uk:5000/INSTA
    Username is     pax
    Password is     never_you_mind

আপনার নির্দিষ্ট ক্ষেত্রে, আপনি এর মতো কিছু ব্যবহার করতে পারেন:

$ cat config.data
    export p_p1=val1
    export p_p2=val2
$ cat go.bash
    . ./config.data
    echo "select * from dbtable where p1 = '$p_p1' and p2 like '$p_p2%' order by p1"
$ bash go.bash
    select * from dbtable where p1 = 'val1' and p2 like 'val2%' order by p1

তারপরে মাইএসকিউএল এবং ভয়েলায় go.bash এর আউটপুটটি পাইপ করুন, আশা করি আপনি আপনার ডাটাবেসটি ধ্বংস করবেন না :-)।


1
আপনার কনফিগারডাটা ফাইল থেকে ভেরিয়েবলগুলি রফতানি করতে হবে না; কেবলমাত্র সেগুলি সেট করার জন্য এটি যথেষ্ট। আপনি কোনও মুহুর্তে টেম্পলেট ফাইলটি পড়ছেন বলে মনে হয় না। অথবা, সম্ভবত, টেমপ্লেট ফাইলটি পরিবর্তিত হয়েছে এবং এতে 'প্রতিধ্বনি' ক্রিয়াকলাপ রয়েছে ... বা আমি কিছু অনুপস্থিত?
জোনাথন লেফলার

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

1
"এর প্রতিধ্বনি বিবৃতি সহ স্বয়ং স্ক্রিপ্ট" কোনও টেমপ্লেট নয়: এটি একটি স্ক্রিপ্ট। মনে readibility (এবং maintainability) <XML টাইপ = "$ প্রকার"> এবং প্রতিধ্বনি '<XML টাইপ = "' $ প্রকার '">' মধ্যে পার্থক্য
পিয়ের-অলিভিয়ের Vares

1
@ পিয়েরে, আমার কনফিগার স্ক্রিপ্টে কোনও প্রতিধ্বনি নেই, তারা কেবল রফতানি করছে, এবং আমি দেখিয়েছি যে কীভাবে আপনি প্রাক-প্রসেসিংয়ের স্বল্প পরিমাণে এড়াতে পারবেন তাও can যদি আপনি আমার অন্যান্য স্ক্রিপ্টগুলিতে ইকো স্টেটমেন্টের কথা বলছেন (যেমন go.bash), আপনি লাঠিটির ভুল শেষ পেয়েছেন - এগুলি সমাধানের অংশ নয়, তারা কেবল ভেরিয়েবলগুলি দেখানোর এক উপায়'re সঠিকভাবে সেট করুন।
প্যাক্সডিয়াবলো

1
@ প্যাক্সিয়াব্লো: মনে হচ্ছে আপনি এই প্রশ্নটি ভুলে গেছেন: << আমি মাইএসকিউএল >> "টেমপ্লেট" ফাইলের আউটপুটটি পাইপ করতে চাইছি >> সুতরাং একটি টেম্পলেট ব্যবহার করা প্রশ্ন, এটি "কাঠির ভুল শেষ" নয়। এক্সপোর্ট ভেরিয়েবল এবং তাদের অন্য কোনো লিপিতে অনুনাদী মাত্র প্রশ্নের উত্তর নেই এ সব
পিয়ের-অলিভিয়ের Vares

0

ব্যাকআপ সহ সম্ভাব্য একাধিক ফাইলের পার্ল সম্পাদনা।

  perl -e 's/\$\{([^}]+)\}/defined $ENV{$1} ? $ENV{$1} : ""/eg' \
    -i.orig \
    -p config/test/*
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.