別のスクリプトのコンテンツとして使用するために変数をエスケープします


18

この質問は、適切にエスケープされた文字列リテラルの書き方に関するものではありません。スクリプト内または他のプログラムで直接使用するために変数をエスケープする方法に関するものではない関連する質問は見つかりませんでした。

私の目標は、スクリプトが他のスクリプトを生成できるようにすることです。これは、生成されたスクリプト内のタスクが別のマシン上で0 回からn回実行され、それらの生成元のデータが実行前に(再び)変更される可能性があるため、ネットワークを介して直接操作を行うためですうまくいかない。

単一引用符などの特殊文字を含む可能性がある既知の変数がある場合、完全にエスケープされた文字列リテラルとして書き出す必要があります。たとえば、生成されたスクリプトにfoo含まれる変数bar'bazは次のようになります。

qux='bar'\''baz'

これは"qux=$foo_esc"、スクリプトの他の行に追加することによって書き込まれます。私はこのようにPerlを使用してそれをやった:

foo_esc="'`perl -pe 's/('\'')/\\1\\\\\\1\\1/g' <<<"$foo"`'"

しかし、これはやり過ぎのようです。

私はbashだけでそれを行うことに成功していません。私はこれらの多くのバリエーションを試しました:

foo_esc="'${file//\'/\'\\\'\'}'"
foo_esc="'${file//\'/'\\''}'"

しかし、余分なスラッシュが出力に表示されるか(私が実行した場合echo "$foo")、構文エラーが発生します(シェルから実行された場合、さらに入力が必要になります)。


aliasおよび/またはsetかなり普遍的に
-mikeserv

@mikeserv申し訳ありませんが、どういう意味かわかりません。
ウォルフ

alias "varname=$varname" varnameまたはvar=value set
mikeserv

2
@mikeservそれは、あなたの提案が何をすべきかを理解するのに十分なコンテキストではなく、また変数をエスケープする一般的な方法としてそれを使用する方法でもありません。それは解決された問題です、仲間。
ウォルフ

回答:


25

Bashには、まさにこの場合のパラメーター拡張オプションがあります

${parameter@Q}展開は、入力として再利用できる形式で引用されたパラメーターの値である文字列です。

したがって、この場合:

foo_esc="${foo@Q}"

これはBash 4.4以降でサポートされています。他の形式の展開、および完全な割り当てステートメントを具体的に生成するためのオプションもいくつかあります(@A)。


7
きちんとしているが、4.2のみを提供しbad substitutionます。
ウォルフ

3
Zシェルに相当するのは"${foo:q}"です。
JdeBP

本当に命を救え!"${foo@Q}"動作します!
ハオ

Zシェルに相当する@JdeBPは機能しません。zshの他のアイデアはありますか?
スティーブンショー

1
私は答えを見つけました:「$ {(@ qq)foo}」
スティーブンショー

10

Bashはフォーマット指定子をprintf備えたビルトインを提供し%qます。これは、古い(<4.0)バージョンのBashでもシェルエスケープを実行します。

printf '[%q]\n' "Ne'er do well"
# Prints [Ne\'er\ do\ well]

printf '[%q]\n' 'Sneaky injection $( whoami ) `ls /root`'
# Prints [Sneaky\ injection\ \$\(\ whoami\ \)\ \`ls\ /root\`]

このトリックは、関数からデータの配列を返すためにも使用できます。

function getData()
{
  printf '%q ' "He'll say hi" 'or `whoami`' 'and then $( byebye )'
}

declare -a DATA="( $( getData ) )"
printf 'DATA: [%q]\n' "${DATA[@]}"
# Prints:
# DATA: [He\'ll\ say\ hi]
# DATA: [or\ \`whoami\`]
# DATA: [and\ then\ \$\(\ byebye\ \)]

Bash printfビルトインはprintf、ほとんどのUnixライクなオペレーティングシステムにバンドルされているユーティリティとは異なることに注意してください。何らかの理由で、printfコマンドが組み込みコマンドではなくユーティリティを呼び出す場合は、代わりにいつでも実行できbuiltin printfます。


印刷する必要があるもの'Ne'\''er do well'、つまり出力に引用符が含まれる場合など、それがどのように役立つかはわかりません。
ウォルフ

1
@Walf 2つの形式が同等であり、どちらも完全に安全であることを理解していないと思います。例えば、[[ 'Ne'\''er do well' == Ne\'er\ do\ well ]] && echo 'equivalent!'エコーしますequivalent!
デジェイクレイトン

私はそれを見逃しました:Pしかし、私は構文が強調されたビューア/エディタで読みやすいので、引用されたフォームを好みます。
ウォルフ

@Walfは、あなたのアプローチがかなり危険であるようです。あなたのPerlの例では、不必要な先行空文字列(最初の2つの一重引用符)と不適切な末尾の一重引用符を含むような値を渡すと'hello'間違った値''\''hello''になることを考えると、
デジェイクレイトン

1
@Walfは、明確化のために、$'escape-these-chars'であるANSI-C引用指定された文字列内のすべての文字がエスケープされる原因となるバッシュの特徴。したがって、ファイル名内に改行を含む文字列リテラルを簡単に作成するには(たとえば$'first-line\nsecond-line')\nこの構成内で使用します。
DejayClayton

7

RTFMをしなかったと思います。次のように実行できます。

q_mid=\'\\\'\'
foo_esc="'${foo//\'/$q_mid}'"

その後echo "$foo_esc"、期待を与えます'bar'\''baz'


私はそれを実際にどのように使用しているのですか?

function esc_var {
    local mid_q=\'\\\'\'
    printf '%s' "'${1//\'/$mid_q}'"
}

...

foo_esc="`esc_var "$foo"`"

これを変更printfして、Dejayのソリューションの組み込みを使用します。

function esc_vars {
    printf '%q' "$@"
}

3
私のバージョンがサポートしていれば、@ michael-homerのソリューションを使用します。
ウォルフ

3

var値を引用するには、いくつかの解決策があります。

  1. エイリアス
    ほとんどのシェル(エイリアスが利用できる場合)(csh、tcsh、およびおそらく他のcshを除く):

    $ alias qux=bar\'baz
    $ alias qux
    qux='bar'\''baz'

    はい、これはshダッシュや灰のような多くのようなシェルで動作します。

  2. セット
    ほとんどのシェルでも(再び、CSHません):

    $ qux=bar\'baz
    $ set | grep '^qux='
    qux='bar'\''baz'
  3. タイプセット
    いくつかのシェル(少なくともksh、bash、zsh):

    $ qux=bar\'baz
    $ typeset -p qux
    typeset qux='bar'\''baz'             # this is zsh, quoting style may
                                         # be different for other shells.

  4. 最初にエクスポート:

    export qux=bar\'baz

    次に使用します:
    export -p | grep 'qux=' export -p | grep 'qux='
    export -p qux

  5. quote
    echo "${qux@Q}"
    echo "${(qq)qux}" #1〜4個のqを使用できます。


エイリアスのアプローチは賢く、POSIXで指定されているようです。最大限の移植性を得るには、これが道だと思います。私は、埋め込み改行を含む変数に関係するgrepexportまたはそれsetを壊す可能性がある提案を信じています。
jw013
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.