जटिल पाठ फ़ाइलों में शेल चरों को कैसे प्रतिस्थापित करें


89

मेरे पास कई पाठ फाइलें हैं जिनमें मैंने शेल चर (उदाहरण के लिए $ VAR1 या $ VAR2) पेश किए हैं।

मैं उन फ़ाइलों (एक-एक करके) को लेना चाहता हूं और उन्हें नई फाइलों में सहेजना चाहता हूं, जहां सभी चर प्रतिस्थापित किए गए होते।

ऐसा करने के लिए, मैंने निम्नलिखित शेल स्क्रिप्ट का उपयोग किया (StackOverflow पर पाया गया):

while read line
do
    eval echo "$line" >> destination.txt
done < "source.txt"

यह बहुत ही बुनियादी फाइलों पर बहुत अच्छी तरह से काम करता है।

लेकिन अधिक जटिल फाइलों पर, "eval" कमांड बहुत कुछ करता है:

  • "#" से शुरू होने वाली रेखाएं छोड़ दी जाती हैं

  • XML फ़ाइलें पार्स करने से त्रुटियों का परिणाम होता है

इसे करने का कोई बेहतर तरीका है? (शेल स्क्रिप्ट में ... मुझे पता है कि यह आसानी से चींटी के साथ किया जाता है)

सधन्यवाद

जवाबों:


205

देख रहे हैं, यह मेरे सिस्टम पर निकलता है एक envsubstकमांड है जो गेटटेक्स्ट-बेस पैकेज का हिस्सा है।

तो, यह आसान बनाता है:

envsubst < "source.txt" > "destination.txt"

नोट आप दोनों के लिए एक ही फाइल का उपयोग करना चाहते हैं, तो आप moreutil की तरह कुछ का उपयोग करना होगा sponge, के रूप में जॉनी Utahh ने सुझाव दिया: envsubst < "source.txt" | sponge "source.txt"। (क्योंकि शेल रीडायरेक्ट उसके पढ़ने से पहले फ़ाइल को खाली कर देगा।)


4
महान! लेकिन यह केवल पर्यावरण चर के लिए काम करता है। मैं उन चर के साथ कैसे काम कर सकता हूं जो मेरी .sh स्क्रिप्ट में घोषित किए गए हैं?
बेन

12
@Ben: उपयोग 'निर्यात' हर चर आप envsubst में उपयोग करना चाहते हैं के लिए (envsubst कॉल करने से पहले)
Tlo


3
@user_mda जहां आउटपुट जाता है।
derobert

4
चेतावनी: यदि चर विस्तार के बाहर source.txtकोई भी $वर्ण हैं, envsubstतो ये भी बदल देंगे और इनसे बचने का कोई तरीका नहीं है $। आम (बदसूरत) वर्कअराउंड है export DOLLAR="$"
कोस

67

उत्तर 2 के संदर्भ में, जब चर्चा करते समय, आपने पूछा:

मैं उन चर के साथ कैसे काम कर सकता हूं जो मेरी .sh स्क्रिप्ट में घोषित किए गए हैं?

जवाब है कि आपको कॉल करने से पहले बस अपने वेरिएबल को एक्सपोर्ट करना होगा envsubst

आप envsubst SHELL_FORMATतर्क का उपयोग करते हुए इनपुट में प्रतिस्थापित होने वाले चर स्ट्रिंग को भी सीमित कर सकते हैं (इनपुट में स्ट्रिंग के अनपेक्षित प्रतिस्थापन से बचने के लिए एक सामान्य शेल चर मान के साथ - जैसे$HOME )।

उदाहरण के लिए:

export VAR1='somevalue' VAR2='someothervalue'
MYVARS='$VAR1:$VAR2'

envsubst "$MYVARS" <source.txt >destination.txt

सभी उदाहरणों का स्थान ले लेगा $VAR1और $VAR2(और केवल VAR1और VAR2में) source.txtके साथ 'somevalue'और 'someothervalue'क्रमशः।


15
एकल उद्धरण 'जो सेट करने के लिए उपयोग किए MYVARSजाते हैं, वे महत्वपूर्ण हैं
मार्क Lakata

ध्यान दें कि export, envsubstया पाठ के स्थानापन्न बड़े होने पर कोई भी इंटरलेविंग कमांड विफल हो सकती है। reference.
बिशप

@ram ऐसा इसलिए है क्योंकि SHELL_FORMATतर्क (यानी "$MYVARS") को छोड़ने से सभी निर्यात किए गए चर प्रतिस्थापित किए जा सकते हैं। अगर आपको यही चाहिए, तो कोई चिंता नहीं।
थियागो फिगुएइरो

14

मुझे पता है कि यह विषय पुराना है, लेकिन मेरे पास चर निर्यात किए बिना एक सरल कार्य समाधान है। एक oneliner हो सकता है, लेकिन मैं \लाइन के अंत का उपयोग करके विभाजित करना पसंद करता हूं ।

var1='myVar1'\
var2=2\
var3=${var1}\
envsubst '$var1,$var3' < "source.txt" > "destination.txt"

#         ^^^^^^^^^^^    ^^^^^^^^^^     ^^^^^^^^^^^^^^^
# define which to replace   input            output

चर को उसी रेखा के रूप में परिभाषित किया जाना चाहिए envsubst किया जाना चाहिए जैसा कि पर्यावरण चर के रूप में माना जाता है।

'$var1,$var3'केवल निर्दिष्ट लोगों को बदलने के लिए वैकल्पिक है। एक इनपुट फ़ाइल की कल्पना करें ${VARIABLE_USED_BY_JENKINS}जिसमें प्रतिस्थापित नहीं किया जाना चाहिए।


8
  1. अपने ईएनवी चर को परिभाषित करें
$ export MY_ENV_VAR=congratulation
  1. निम्नलिखित सामग्री के साथ टेम्पलेट फ़ाइल (। Inxt ) बनाएं
$MY_ENV_VAR

आप अपने सिस्टम द्वारा परिभाषित अन्य सभी ईएनवी वैरिएबल का भी उपयोग कर सकते हैं जैसे (लिनक्स में) $ TERM, $ SHELL, $ HOME ...

  1. इस कमांड को अपने। Inxt फ़ाइल में सभी env-variables को रगड़ने के लिए और परिणाम को out.txt पर लिखने के लिए चलाएँ
$ envsubst "`printf '${%s} ' $(sh -c "env|cut -d'=' -f1")`" < in.txt > out.txt
  1. Out.txt फ़ाइल की सामग्री की जाँच करें
$ cat out.txt

और आपको "बधाई" देखना चाहिए।


0

यदि आप वास्तव में केवल बैश (और सेड) का उपयोग करना चाहते हैं, तो मैं आपके प्रत्येक पर्यावरण चर (जैसे कि setपॉक्सिक्स मोड में लौटा ) के माध्यम से जाऊंगा और उस सेड के लिए एक गुच्छा का निर्माण करूंगा -e 'regex', जिसे ए द्वारा समाप्त किया गया है -e 's/\$[a-zA-Z_][a-zA-Z0-9_]*//g', फिर वह सब पास करें sed।

पर्ल एक अच्छा काम करेगा हालांकि, आपके पास एक वेरिएंट के रूप में पर्यावरण वेरिएंट तक पहुंच है और आप निष्पादन योग्य प्रतिस्थापन कर सकते हैं, इसलिए आप केवल एक बार किसी भी पर्यावरण चर से मेल खाते हैं।


क्यों किसी को इस तरह एक जवाब देना होगा ??? -perl -pi -e 'foreach $key(sort keys %ENV){ s/\$$key/$ENV{$key}/g}' "$main_tf_file"
योर्डन जॉर्जिएव

0

वास्तव में आपको अपने readको बदलने की आवश्यकता हैread -r जो यह बैकस्लैश उपेक्षा कर देगा।

इसके अलावा, आपको उद्धरण और बैकस्लैश से बचना चाहिए। इसलिए

while read -r line; do
  line="${line//\\/\\\\}"
  line="${line//\"/\\\"}"
  line="${line//\`/\\\`}"
  eval echo "\"$line\""
done > destination.txt < source.txt

हालांकि अभी भी विस्तार करने के लिए एक भयानक तरीका है।


वास्तव में, यह जोखिम है जब एक फ़ाइल पर "eval" किया जाता है जिसमें बुरा कोड हो सकता है
बेन

0

सभी आवश्यक चर निर्यात करें और फिर एक पर्ल ऑनलाइनर का उपयोग करें

TEXT=$(echo "$TEXT"|perl -wpne 's#\${?(\w+)}?# $ENV{$1} // $& #ge;')

यह TEXT में मौजूद सभी ENV वैरिएबल को वास्तविक मानों से बदल देगा। उद्धरण भी संरक्षित हैं :)


0

यदि आप चाहते हैं कि सभी तरह के नॉन इनवे वैरिएबल्स को रखते हुए आप अपने श्रोत फ़ाइलों में env वेरिएबल्स को बदल दें, तो आप निम्न कमांड का उपयोग कर सकते हैं:

envsubst "$(printf '${%s} ' $(env | sed 's/=.*//'))" < source.txt > destination.txt

केवल विशिष्ट चर की जगह के लिए वाक्यविन्यास यहाँ समझाया गया है । उपरोक्त कमांड सभी परिभाषित चर को सूचीबद्ध करने और फिर इसे पास करने के लिए एक उप-शेल का उपयोग कर रहा हैenvsubst

तो अगर वहाँ एक परिभाषित एनवी चर कहा जाता है $NAME, और आपकी source.txtफ़ाइल इस तरह दिखती है:

Hello $NAME
Your balance is 123 ($USD)

destination.txtहो जाएगा:

Hello Arik
Your balance is 123 ($USD)

ध्यान दें कि $NAMEबदल दिया गया है और $USDअछूता रह गया है


0

पेरल बाइनरी को कॉल करें, प्रति पंक्ति मोड ( -piए) में खोज और प्रतिस्थापित -eकरें एकल उद्धरणों में पर्ल कोड () चलाकर , जो विशेष %ENVहैश की कुंजियों पर निर्भर करता है जिसमें कुंजी के रूप में निर्यात किए गए चर नाम और निर्यात किए गए चर मान हैं कुंजी के मान और प्रत्येक पुनरावृत्ति के लिए सरल एक स्ट्रिंग को प्रतिस्थापित करता है जिसमें $<<key>>इसके साथ होता है <<value>>

 perl -pi -e 'foreach $key(sort keys %ENV){ s/\$$key/$ENV{$key}/g}' file

कैविएट: ऐसे मामलों के लिए एक अतिरिक्त लॉजिक हैंडलिंग की आवश्यकता होती है, जिसमें दो या दो से अधिक संस्करण एक ही स्ट्रिंग से शुरू होते हैं ...


-1

envsubstबिल्कुल वैसा ही लगता है जैसा मैं उपयोग करना चाहता था, लेकिन -vविकल्प ने मुझे थोड़ा हैरान कर दिया।

जबकि envsubst < template.txtठीक काम कर रहा था, विकल्प के साथ -vकाम नहीं कर रहा था:

$ cat /etc/redhat-release
Red Hat Enterprise Linux Server release 7.1 (Maipo)
$ envsubst -V
envsubst (GNU gettext-runtime) 0.18.2
Copyright (C) 2003-2007 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Written by Bruno Haible.

जैसा कि मैंने लिखा, यह काम नहीं कर रहा था:

$ envsubst -v < template.txt
envsubst: missing arguments
$ cat template.txt | envsubst -v
envsubst: missing arguments

मुझे यह काम करने के लिए ऐसा करना पड़ा:

TEXT=`cat template.txt`; envsubst -v "$TEXT"

शायद यह किसी की मदद करे।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.