1. 程式人生 > >shell模板變數替換

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
  1. eval替換$content的值