كيفية استبدال العناصر النائبة ${} في ملف نصي؟
-
03-07-2019 - |
سؤال
أرغب في توجيه إخراج ملف "القالب" إلى MySQL، حيث يحتوي الملف على متغيرات مثل ${dbName}
تتخللها.ما هي الأداة المساعدة لسطر الأوامر لاستبدال هذه الحالات وتفريغ الإخراج إلى الإخراج القياسي؟
المحلول
سد !
ونظرا template.txt:
The number is ${i} The word is ${word}
وعلينا فقط أن أقول:
sed -e "s/\${i}/1/" -e "s/\${word}/dog/" template.txt
وبفضل جوناثان ليفلر للمعلومات لتمرير الحجج -e
متعددة لنفس الاحتجاج sed
.
نصائح أخرى
تحديث
وهنا هو الحل من yottatsa على سؤال مماثل أن يفعل استبدال فقط للمتغيرات مثل $ VAR أو $ {VAR }، وهي قصيرة أونيلينير
i=32 word=foo envsubst < template.txt
وبالطبع إذا <م> <ط / م> و <م> كلمة م> هي في البيئة الخاصة بك، ثم انها مجرد
envsubst < template.txt
في بلدي ماك يبدو تم تثبيته كجزء من gettext م> ومن MacGPG2 م>
قديم الإجابة
وهنا تحسنا في حل من mogsie على سؤال مماثل، يا الحل لا تتطلب منك ESCALE مزدوج ونقلت وmogsie في ذلك، ولكن له هو بطانة واحد!
eval "cat <<EOF
$(<template.txt)
EOF
" 2> /dev/null
والقوة على هذين الحلين هو أن تحصل فقط على أنواع قليلة من التوسعات قذيفة التي لا تحدث عادة $ ((...))، `` ...، و$ (...)، على الرغم من مائل <م> هو م> حرف هروب هنا، ولكن لم يكن لديك ما يدعو للقلق أن إعراب له علة، وأنه لا خطوط متعددة على ما يرام.
استخدم /bin/sh
. إنشاء شيل الصغيرة التي تحدد المتغيرات، ومن ثم تحليل القالب باستخدام قذيفة نفسها. مثل ذلك (تحرير لمعالجة أسطر جديدة بشكل صحيح):
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"
إخراج:
#sh script.sh
the number is 1
the word is dog
وكنت أفكر في هذا مرة أخرى، نظرا للاهتمام الأخيرة، وأعتقد أن الأداة التي كنت أفكر في الأصل من كان <لأ href = "http://www.gnu.org/software/m4/manual/index أتش تي أم أل "يختلط =" noreferrer "> m4
أو المعالج الكلي للautotools. وذلك بدلا من المتغير I المحدد أصلا، وكنت استخدام:
$echo 'I am a DBNAME' | m4 -DDBNAME="database name"
و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 template.txt parsed_file.txt
اقتباس فقرة>وparsed_file.txt
Variable 1 value: value 1
Variable 2 value: value 2
وهنا قال لي حل مع بيرل على أساس الإجابة السابقة، يستبدل متغيرات البيئة:
perl -p -e 's/\$\{(\w+)\}/(exists $ENV{$1}?$ENV{$1}:"missing variable $1")/eg' < infile > outfile
وهنا أ وظيفة باش قوية ذلك - على الرغم من استخدام eval
- يجب أن تكون آمنة للاستخدام.
الجميع ${varName}
يتم توسيع المراجع المتغيرة في نص الإدخال بناءً على متغيرات shell المستدعية.
لا شيء آخر تم توسيعه:لا المراجع المتغيرة التي أسمائها لا المغلقة في {...}
(مثل $varName
)، ولا بدائل الأوامر ($(...)
وبناء الجملة التراثية `...`
)، ولا البدائل الحسابية ($((...))
وبناء الجملة التراثية $[...]
).
لعلاج أ $
كحرفٍ، \
- الهروب منه؛على سبيل المثال:\${HOME}
لاحظ أنه يتم قبول الإدخال فقط عبر com.stdin.
مثال:
$ 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
أحرف التحكم موجودة في الإدخال، لأن تلك الأحرف.يتم استخدامها داخليًا - منذ العمليات الوظيفية نص, ، يجب أن يكون هذا افتراضًا آمنًا.
إذا كنت مفتوحة لاستخدام بيرل ، من شأنه أن يكون اقتراحي. على الرغم من أن هناك ربما بعض ااا و / أو <وأ href = "HTTP: // داخلي. wikipedia.org/wiki/AWK "يختلط =" نوفولو noreferrer "> AWK الخبراء انه من المحتمل ان تعرف كيف تفعل هذا أسهل بكثير. إذا كان لديك تعيين أكثر تعقيدا مع أكثر من مجرد 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
إنشاء 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
و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
وأود أن أقترح استخدام شيء من هذا القبيل على سيجيل : ل https://github.com/gliderlabs/sigil
ويتم تصنيف أن ثنائي واحد، لذلك فمن السهل للغاية لتثبيت على أنظمة.
وبعد ذلك يمكنك القيام بسيطة أونيلينير كما يلي:
cat my-file.conf.template | sigil -p $(env) > my-file.conf
وهذا هو أكثر أمانا من eval
وأسهل ثم استخدام التعابير المنطقية أو sed
ولقد وجدت هذا الموضوع في حين يتساءل نفس الشيء. من وحي لي لهذا (الحذر مع backticks)
$ echo $MYTEST
pass!
$ cat FILE
hello $MYTEST world
$ eval echo `cat FILE`
hello pass! world
والكثير من الخيارات هنا، ولكن أحسب أن كنت إرم الألغام على الكومة. ومن بيرل القائمة، ويستهدف فقط متغيرات النموذج $ {...}، ويأخذ الملف لمعالجة كحجة و إخراج الملف المحول على المعياري:
use Env;
Env::import();
while(<>) { $_ =~ s/(\${\w+})/$1/eeg; $text .= $_; }
print "$text";
وبطبيعة الحال أنا لا حقا شخص بيرل، لذلك يمكن أن يكون هناك بسهولة الخلل القاتل (يعمل بالنسبة لي على الرغم من).
ويمكن ان يتم ذلك في سحق نفسه إذا كان لديك السيطرة على شكل ملف التكوين. تحتاج فقط إلى المصدر ( ".") ملف التكوين بدلا من المستوى الفرعي ذلك. يضمن يتم إنشاء المتغيرات في سياق قذيفة الحالية (وتستمر في الوجود) بدلا من المستوى الفرعي (حيث المتغير تختفي عندما يتم إنهاء المستوى الفرعي).
$ 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 إلى الخلية وفويلا، ونأمل أن لن يدمر قاعدة البيانات الخاصة بك: -)
فيما يلي طريقة لجعل الصدفة تقوم بالاستبدال نيابةً عنك، كما لو تم كتابة محتويات الملف بين علامتي اقتباس مزدوجتين.
باستخدام مثال template.txt مع المحتويات:
The number is ${i}
The word is ${word}
سيؤدي السطر التالي إلى قيام الصدفة باستيفاء محتويات template.txt وكتابة النتيجة إلى الوضع القياسي.
i='1' word='dog' sh -c 'echo "'"$(cat template.txt)"'"'
توضيح:
i
وword
يتم تمريرها كمتغيرات البيئة التي تم تحديدها لتنفيذ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
هي متغيرات البيئة المحددة.