Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
2.2k views
in Technique[技术] by (71.8m points)

linux - Replace bash variables in template file

I am attempting to use Bash in order to run a form of an install process. During this process, a configuration file is copied and certain values are replaced inside of it. Such a config can be found below:

server {
    listen 80;
    root ${INSTALLPATH};
    server_name ${SITEURL};

    client_max_body_size 20m;
    client_body_timeout 120s;

    location / {
        try_files /public/router.php =404;
        fastcgi_split_path_info ^(.+?.php)(/.*)$;
        fastcgi_pass ${PHPSERV};
        fastcgi_index router.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include /etc/nginx/fastcgi_params;
    }

    location /assets {
        try_files /app/$uri =404;
    }

}

#Enables HTTPS access
#This requires you to install certificates and is not enabled by default
#If you wish to enable HTTPS, uncomment (remove the #s) from the below lines
#And change the ssl_certificate and ssl_certificate_key to point to the     correct
#certificates.

#server {
#    listen 443;
#    root ${INSTALLPATH};
#    server_name ${SITEURL};
#
#    ssl on;
#    ssl_certificate     /etc/nginx/ssl/site.crt;
#    ssl_certificate_key /etc/nginx/ssl/site.key;
#
#    location / {
#        try_files /public/router.php =404;
#        fastcgi_split_path_info ^(.+?.php)(/.*)$;
#        fastcgi_pass ${PHPSERV};
#        fastcgi_index router.php;
#        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
#        include /etc/nginx/fastcgi_params;
#    }
#
#    location /assets {
#        try_files /app/$uri =404;
#    }
#
#}

I have been finding that most examples stem off the use of eval, and I have tried using that to do this replacement, however it appears that the file here does not properly expand, and bash tries to execute some stuff and can't.

Currently, I have this

INSTALLPATH="/var/www/html/mycustomsite/"
PHPSERV="127.0.0.1:9000"
SITEURL="example.com"

while read -r line; do
    eval echo -e "${line}"
done < template

However, this does not properly replace the values that are declared, nor does it generate the file correctly. It loses for example any line that starts with # and tries to execute others (along with losing some spacing).

What would be the correct way to do this, using just Bash and commands available on most Linux systems?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Security tips

This don't take care of security issues! Using eval is evil!

The compatible answer is not better!

Of course, you have to be confident about the content of your template!!

If else, try using ! (see my last answer)

Quick way only!:

Under you can simply:

eval "INSTALLPATH='/somepath/somewhere' SITEURL='example.com' PHPSERV='127.0.0.1:9000'; echo "$(<template)""

or

eval "INSTALLPATH='/somepath/somewhere'
    SITEURL='example.com'
    PHPSERV='127.0.0.1:9000';
    echo "$(<template)""

As you're using eval, you could store your resulting config file into one variable:

eval "INSTALLPATH='/somepath/somewhere'
    SITEURL='example.com'
    PHPSERV='127.0.0.1:9000';
    cfgBody="$(<template)""

Then

echo "$cfgBody"

and/or

echo "$cfgBody" >/cfgpath/cfgfile

Doing this into a loop

tmplBody="$(<template)"
while read INSTALLPATH SITEURL PHPSERV CFGFILE;do
    [ "$CFGFILE" ] && eval "echo "$tmplBody"" >"$CFGFILE"
  done <<<"
    /somepath/somewhere            example.com  127.0.0.1:9000  /tmp/file1
    '/some other path/elsewhere' sample2.com  127.0.0.1:9001  /tmp/file2
"

Note: On second line, there are escaped spaces (prepanded with a backshash and quotes '. The backslash tell read to not split the variable, and the quotes have to be added into the resulting /tmp/file2.

Soft way (compatible answer)

Under , you may do this way:

#!/bin/sh

(
    cat <<eohead
    #!/bin/sh
    INSTALLPATH='/somepath/somewhere'
    SITEURL='example.com'
    PHPSERV='127.0.0.1:9000';
    cat <<eof
eohead
    cat template
    echo eof
) | /bin/sh

This don't require bash, was tested under and .

Without eval !

sedcmd=''
for var in INSTALLPATH SITEURL PHPSERV;do
    printf -v sc 's/${%s}/%s/;' $var "${!var////\/}"
    sedcmd+="$sc"
  done
sed -e "$sedcmd" <template

Could work into a loop:

while read INSTALLPATH SITEURL PHPSERV CFGFILE;do
    if  [ "$CFGFILE" ] ;then
        sedcmd=''
        for var in INSTALLPATH SITEURL PHPSERV;do
            printf -v sc 's/${%s}/%s/;' $var "${!var////\/}"
            sedcmd+="$sc"
          done
        sed -e "$sedcmd" <template >"$CFGFILE"
      fi
  done <<<"
    /somepath/somewhere             example.com  127.0.0.1:9000  /tmp/file1
    '/some other path/elsewhere'  sample2.com  127.0.0.1:9001  /tmp/file2
"

Compatible answer, using sed

This could work without so called bashisms, into a loop:

#!/bin/sh

while read INSTALLPATH SITEURL PHPSERV CFGFILE;do

    sedcmd="s|\${INSTALLPATH}|${INSTALLPATH}|;"
    sedcmd="${sedcmd}s|\${SITEURL}|${SITEURL}|;"
    sedcmd="${sedcmd}s|\${PHPSERV}|${PHPSERV}|;"

    sed -e "$sedcmd" template >"$CFGFILE"

  done <<eof
    /somepath/somewhere             example.com  127.0.0.1:9000  /tmp/file1
    '/some other path/elsewhere'  sample2.com  127.0.0.1:9001  /tmp/file2
eof

Comparing outputs:

diff -u99 /tmp/file{1,2}
--- /tmp/file1        2015-05-31 11:02:03.407463963 +0200
+++ /tmp/file2        2015-05-31 11:02:03.407463963 +0200
@@ -1,22 +1,22 @@
 server {
     listen 80;
-    root /somepath/somewhere;
-    server_name example.com;
+    root '/some other path/elsewhere';
+    server_name sample2.com;

     client_max_body_size 20m;
     client_body_timeout 120s;

     location / {
         try_files /public/router.php =404;
         fastcgi_split_path_info ^(.+?.php)(/.*)$;
-        fastcgi_pass 127.0.0.1:9000;
+        fastcgi_pass 127.0.0.1:9001;
         fastcgi_index router.php;
         fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
         include /etc/nginx/fastcgi_params;
     }

     location /assets {
         try_files /app/$uri =404;
     }

 }

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...