2017-11-01 7 views
1

JQを使ってシェルスクリプトでJSONを読んでいます。ここでは、シェルスクリプトの変数$ HOME、$ HOST、$ PEMFILEをその場で解釈することができません。シェルスクリプト内で変数をその場で解釈するにはどうすればよいですか?

JSONファイル:

{ 
    "script": { 
    "install": "${HOME}/lib/install.sh $HOST $PEMFILE", 
    "Setup": "${HOME}/lib/setup.sh $HOST $PEMFILE $VAR1 $VAR2" 
    } 

} 

シェルスクリプト:

#!/bin/bash 
examplefile="../lib/example.json" 
HOST=ec2-..-...-...-...us-west-2.compute.amazonaws.com 
PEMFILE=${HOME}/test.pem 

installScript=($(jq '.script.install' $examplefile)) 
bash "$installScript" 

私はJSONを変更せずにその場でこれらの変数を解釈できる方法はありますか?

P.S私はevalを使用したくありません。ここ

+1

それを置き換えるパラメータ置換、あなたはJSONを変更する必要があります。任意のコマンドを1つの文字列として格納することは悪い考えです。そのまま展開されるパラメータは正しく引用されません。 – chepner

+0

また、 'bash -c'を使うか、' '$ installScript''を実行するスクリプトの名前として扱います。 – chepner

+0

'installScript =($(jq '.script.install' $ examplefile))'はここでは奇妙な形です。文字列を文字列で配列に分割した後、 'bash 'に入れます$ installScript" youその配列の最初の要素のみを展開します。そして、文字列分割は一般的に手元にあるバグであり、[BashFAQ#50](http://mywiki.wooledge.org/BashFAQ/050)を参照してください。 –

答えて

3

は交換を実行するためにenvgsubを用いた溶液です。

envは、変数がシェル変数ではなく環境変数として渡される必要があることに注意してください。

#!/bin/bash 

examplefile="../lib/example.json" 
HOST=ec2-..-...-...-...us-west-2.compute.amazonaws.com 
PEMFILE=${HOME}/test.pem 

export HOST 
export PEMFILE 
installScript=$(jq -Mr ' 
    .script.install | gsub("(?<x>[$][{]?\\w+[}]?)"; env[.x|gsub("[${}]+";"")]) 
' $examplefile) 

echo $installScript 

サンプル出力

/home/runner/lib/install.sh ec2-..-...-...-...us-west-2.compute.amazonaws.com /home/runner/test.pem 

Try it online!

+0

入力がJSON(jqコードではなく)であることを編集前に指定していたとしても、元のバージョンがそれに応答するかどうかはわかりません。しかし、修正されたバージョンは良いです - おそらく、あなたはそれを念頭に置くかもしれません。 –

+0

これは意味があります。私は私の元の提案を置き換えました。ありがとうございました! – jq170727

+0

(サムズアップ)ところで、変数を割り当てる前に 'set -a'を追加すると自動的に' export'されます。 –

0
#!/bin/sh 

TMP=$(mktemp /tmp/$$.XXX) 

cat<<E_O_F > $TMP 
cat <<EOF 
$(cat so-dollar-variables.json) 
EOF 
E_O_F 

. $TMP 

/bin/rm "$TMP" 
+1

'/ tmp/$$。txt'は危険です - PIDは攻撃者が予測するのが簡単です。あなたのスクリプトが 'root'として実行されていることを知っていれば、特権を持たないユーザ(' '誰も' ')として実行しているコードを制御する人は、ルート所有のファイルを指し示す可能性のある/削除/上書きする。 –

+0

ほとんどのバージョンのmktemp私は、テンプレートに少なくとも6つのプレースホルダ/フィラー文字を必要としていることを認識しています。 –

3

それはGNUユーティリティenvsubst使用して簡単です:

installScript=$(jq -r '.script.install' "$examplefile" | envsubst) 
+2

これは現在、私の+1を持っている2つのアプローチの1つです。しかし、それを見て、私はそれが警告なしで推奨されるべきものかどうか確信していません - シェルコマンドとして結果を解析する前に、変数をコードで置き換えるのは確かに安全です交換自体をしてください。 –

3

具体的な解決策を

ここで述べた問題に対するjqの解決法がありますが、 "グローバルな"環境変数に対してのみ機能します。

def substitute: 
    gsub("\\${HOME}"; env.HOME) 
    | gsub("\\$HOST"; env.HOST) 
    | gsub("\\$PEMFILE"; env.PEMFILE) 
    | gsub("\\$VAR1"; env.VAR1) 
    | gsub("\\$VAR2"; env.VAR2) 
    ; 

walk(if type=="string" then substitute else . end) 

あなたJQは、すでに示したように、上記の溶液は少し脆いですが、それは簡単にロバストまたは一般化することができ、あなたのJQをアップグレードするか、https://github.com/stedolan/jq/blob/master/src/builtin.jq

からデフをSNARFしてくださいいずれか、walk/1を持っていない場合次のセクションで説明します。

一般的なソリューション

walk(if type == "string" 
    then gsub("\\$(?<x>[A-Za-z_][A-Za-z0-9_]+)"; "\(env[.x])") 
      | gsub("\\${(?<x>[A-Za-z_][A-Za-z0-9_]+)}"; "\(env[.x])") 
    else . end) 
0

私は年間のオンとオフこれを打ってきました。私はようやくまともな純粋なbashのソリューションを持っていると思う:

  1. 正規表現:正規表現のマッチングと間接的なパラメータ置換

    # read the file 
    json=$(< file.json) 
    echo step 0 
    echo "$json" 
    
    # set the relevant vars, just plain shell variables 
    HOST=_host_ 
    PEMFILE=_pemfile_ 
    VAR1=_var1_ 
    VAR2=_var2_ 
    
    # replace '$var' forms 
    while [[ $json =~ ("$"([[:alnum:]_]+)) ]]; do 
        json=${json//${BASH_REMATCH[1]}/${!BASH_REMATCH[2]}} 
    done; 
    echo 
    echo step 1 
    echo "$json" 
    
    # replace '${var}' forms 
    while [[ $json =~ ("$""{"([[:alnum:]_]+)"}") ]]; do 
        json=${json//${BASH_REMATCH[1]}/${!BASH_REMATCH[2]}} 
    done 
    echo 
    echo step 2 
    echo "$json" 
    

    出力

    step 0 
    { 
        "script": { 
        "install": "${HOME}/lib/install.sh $HOST $PEMFILE", 
        "Setup": "${HOME}/lib/setup.sh $HOST $PEMFILE $VAR1 $VAR2" 
        } 
    
    } 
    
    step 1 
    { 
        "script": { 
        "install": "${HOME}/lib/install.sh _host_ _pemfile_", 
        "Setup": "${HOME}/lib/setup.sh _host_ _pemfile_ _var1_ _var2_" 
        } 
    
    } 
    
    step 2 
    { 
        "script": { 
        "install": "/home/jackman/lib/install.sh _host_ _pemfile_", 
        "Setup": "/home/jackman/lib/setup.sh _host_ _pemfile_ _var1_ _var2_" 
        } 
    
    } 
    

    魔法があるを使用していますここで私は$VARVARをキャプチャし、

    [[ $json =~ ("$"([[:alnum:]_]+)) ]] 
    # ..........1 2    21 
    
  2. 私は、文字列"$VAR"を検索し、間接的な変数の展開と${!VAR}

    ${json//${BASH_REMATCH[1]}/${!BASH_REMATCH[2]}} 
    
関連する問題