shell模板變數替換
我們經常使用一些模板語言來處理一些變數替換。比如jsp,php,velocity,freemarker,thymeleaf等。那對於shell來說,應該怎樣替換變數呢。有一種很簡單的辦法可以做到。
先來看一個應用場景。在datax是阿里開源的一個異構資料來源同步框架,其配置文件是json的,我想要用shell去呼叫執行pg到pg的資料同步,需要根據我的配置生成對應的配置檔案。這如果用java來做就是維護一個物件,設定value,最後json-encode就好了。要是使用shell,這樣也可以做到:
渲染指令碼
#!/bin/bash SRC_USER_NAME=etl SRC_USER_PWD=etl SRC_SQL="select * from tab" SRC_HOST_IP="192.168.1.1" SRC_HOST_PORT=3306 SRC_DB="abc_db" TAR_USER_NAME="etl2" TAR_USER_PWD="pass2" fields_map="\"a\",\"b\",\"c\"" TAR_HOST_IP="aaaadfsdfdsfjsdjf" TAR_HOST_PORT="5432" TAR_DB="tar_db" TAR_TABLENAME="tbname" eval "cat <<EOF $(< pg2pg.datax.json) EOF " > result.json
模板文件 pg2pg.datax.json
{ "job": { "setting": { "speed": { "byte": 1048576 }, "errorLimit": { "record": 0, "percentage": 0.02 } }, "content": [ { "reader": { "name": "postgresqlreader", "parameter": { "username": "${SRC_USER_NAME}", "password": "${SRC_USER_PWD}", "where": "", "connection": [ { "querySql": [ "${SRC_SQL}" ], "jdbcUrl": [ "jdbc:postgresql://${SRC_HOST_IP}:${SRC_HOST_PORT}/${SRC_DB}" ] } ] } }, "writer": { "name": "postgresqlwriter", "parameter": { "username": "${TAR_USER_NAME}", "password": "${TAR_USER_PWD}", "column": [ ${fields_map} ], "preSql": [ "" ], "connection": [ { "jdbcUrl": "jdbc:postgresql://${TAR_HOST_IP}:${TAR_HOST_PORT}/${TAR_DB}", "table": [ "${TAR_TABLENAME}" ] } ] } } } ] } }
輸出結果
{ "job": { "setting": { "speed": { "byte": 1048576 }, "errorLimit": { "record": 0, "percentage": 0.02 } }, "content": [ { "reader": { "name": "postgresqlreader", "parameter": { "username": "etl", "password": "etl", "where": "", "connection": [ { "querySql": [ "select * from tab" ], "jdbcUrl": [ "jdbc:postgresql://192.168.1.1:3306/abc_db" ] } ] } }, "writer": { "name": "postgresqlwriter", "parameter": { "username": "etl2", "password": "pass2", "column": [ "a","b","c" ], "preSql": [ "" ], "connection": [ { "jdbcUrl": "jdbc:postgresql://aaaadfsdfdsfjsdjf:5432/tar_db", "table": [ "tbname" ] } ] } } } ] } }
核心內容是
eval "cat <<EOF
$(< pg2pg.datax.json)
EOF
" > result.json
其中有幾個語法需要學習下。
第一shell中變數的定義,變數賦值時,等號(=
)`兩邊必須沒有空格。
第二, eval
的用法。
語法:eval cmdLine
eval會對後面的cmdLine進行兩遍掃描,如果第一遍掃描替換變數,然後執行cmdLine.
[[email protected] test]$ set 11 22 33 44
[[email protected] test]$ echo $4
44
[[email protected] test]$ echo $#
4
[[email protected] test]$ echo "\$$#"
$4
[[email protected] test]$ eval echo "\$$#"
44
本組測試中,echo可以讀取變數的第一層定義,所以$#
代表引數個數4,$4
代表第4個引數44。但我們想要直接去最後一個引數,需要使用變數的值作為變數的value。eval就會再次掃描一遍。
第三,cat <<EOF
這是一個多行輸入的操作。
[[email protected] test]$ cat <<EOF
> aaa
> bbb
> ccc
> EOF
aaa
bbb
ccc
EOF代表End Of File,這裡表示輸入結束標誌,<<EOF
表示定義結束符為EOF
,接下來直到輸入EOF時,命令結束。cat就會把內容輸出。cat本來是輸出檔案內容的,這裡把輸入當做臨時檔案處理了。
第四, $(xxx)
表示變數替換,和兩個反引號的效果相同,會執行裡面的命令。所以< pg2pg.datax.json
才會讀取檔案內容。
最後輸入EOF結束內容。需要注意EOF前後不要有空格,必須是回車,不然就不代表最後一個字元了。
為了更加容易理解,可以修改渲染指令碼
content=$(cat pg2pg.datax.json)
eval "cat <<EOF
$content
EOF" > result.json
- eval替換$content的值