テンプレートとして使用するテキストファイルがあります。
Hostname : $HOSTNAME
Host Address : $HOSTADDRESS
私のbashスクリプトは2つの変数を設定し、HOSTNAME
テンプレートHOSTADDRESS
ファイルを読み、次に実行してandをeval
展開します。$HOSTNAME
$HOSTADDRESS
HOSTNAME="SH_SQL_0089"
HOSTADDRESS="172.16.3.44"
TEMPLATE=`cat template.txt`
MESSAGE=`eval echo $TEMPLATE`
結果の値は次のとおりですMESSAGE
。
Hostname : SH_SQL_0089
Host Address : 172.16.3.44
最後の2行を次のように単純化できますか?
MESSAGE=$(cat template.txt | eval echo ????)
私は以下を使用しようとしていますxargs
:
MESSAGE=$( cat template.txt | xargs -i bash -c "eval echo {}" )
$HOSTNAME
ただし、キャリッジリターンを交換して削除するだけです。
これを実行する理由は、3番目の処理ステップを追加し、eval
出力をそのステップにパイプする必要があるためです。とても近いような気がします。
ベストアンサー1
まず、代替は子プロセス(開始プロセス)xargs
で実行されるため、ここでは機能しません。ただし、シェル変数ではなく環境変数のみが子プロセスに渡されます。明らかに、スクリプトの起動時にスクリプト環境にすでに存在しますが、そうではありません。この時点ですべての変数をエクスポートしたい誘惑を受け取ることができますが、それでも多くの引用問題に直面するので、良い解決策ではありません。テンプレートにスペースが含まれている場合、またはスペースを保存したい場合は問題が発生します。bash
xargs
HOSTNAME
HOSTADDRESS
xargs
\"'
さて、現在のコードを見てください。参照の問題を除いて、MESSAGE=`eval echo $TEMPLATE`
コードを書く方法は複雑です。eval MESSAGE=$TEMPLATE
そして引用の問題があります。たとえば、すべてのスペースが縮小されていることがわかります。あなたは聞いたバービーテーブル、そうではありませんか?シェル拡張ルールは複雑ですが、気をつけるためのいくつかのルールがあります。
"$foo"
変数置換とコマンド置換は常に二重引用符で囲まれています"$(bar)"
。引用符を省略する理由を理解している場合は、この規則に違反する可能性があります。$(…)
代わりに`…`
コマンドの置き換えに使用してください。バックティック形式内で引用するのはあいまいで移植性がありませんが、内部的に引用するのは$(…)
一般的です。eval
銃口の下を押すときだけ使用されます。これを行う場合は、注意を払ってできるだけ単純にしてください。
それでは何が間違っている可能性がありますかeval MESSAGE="$TEMPLATE"
?シェルが評価できるようにします。
MESSAGE=Hostname : $HOSTNAME
Host Address : $HOSTADDRESS
このように、値が必要な部分に引用符を入れる必要がありますMESSAGE
。引用符に達する必要があるため、eval
文字通りシェル拡張の最初のステップである必要がありますeval MESSAGE="\"$TEMPLATE\""
。
MESSAGE="Hostname : $HOSTNAME
Host Address : $HOSTADDRESS"
良いですが、今、ボビーテーブルの注入パターンができました。テンプレートに参照が含まれている場合はどうなりますか?その後、引用符をエスケープする必要があります。二重引用符の間の4文字は特別な意味を持ち、その意味を維持する\"$`
には、$
他の3文字の前にバックスラッシュを追加します。
TEMPLATE=$(sed -e 's/[\\"`]/\\&/g' <template.txt)
eval MESSAGE="\"$TEMPLATE\""
これでシェルが評価します
MESSAGE="Hostname : $HOSTNAME
Host Address : $HOSTADDRESS
Name : Bobby \"drop\" O'Tables"
みんな大丈夫です。
ここで正しい引用は、予期しない構文解析の問題を防ぐためです。テンプレートを制御する人はまだシェルアクセス(使用法$(hello)
)を持っています。
シェルスクリプトにテンプレートを含めるには、次のように自然に使用できます。トレドック。
MESSAGE=$(cat <<EOF)
Hostname : $HOSTNAME
Host Address : $HOSTADDRESS
EOF
ただし、外部テンプレートを使用するには2段階の評価を実行する必要があるため、eval
内部heredocsなどのファンキーな操作ではbashの解析を使用することが非常に問題になりますeval
。少なくともbash 4を使用することは間違いなくできる方法がありますが、チャンスをつかむことはお勧めできません。