web-dev-qa-db-ja.com

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

この質問は、適切にエスケープされた文字列リテラルをどのように記述するかについてnotです。スクリプト内または他のプログラムで直接使用するために変数をエスケープする方法に関する問題ではない関連質問を見つけることができませんでした。

私の目標は、スクリプトが他のスクリプトを生成できるようにすることです。これは、生成されたスクリプトのタスクが別のマシンで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"を実行した場合)、またはそれらは構文エラーを引き起こします(シェルから入力された場合、さらに入力が必要です)。

22
Walf

私は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"`"

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

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

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

${parameter@Q}拡張は、入力として再利用できる形式で引用されたparameterの値である文字列です。

したがって、この場合:

foo_esc="${foo@Q}"

これは、Bash 4.4以降でサポートされています。他の形式の展開にもいくつかのオプションがあり、完全な代入ステートメント(@A)。

33
Michael Homer

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

14
Dejay Clayton

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
    _

    次に使用します:
    ksh _export -p | grep 'qux='_ bash _export -p | grep 'qux='_
    zsh _export -p qux_

  5. 見積もり
    bash _echo "${qux@Q}"_
    zshecho "${(qq)qux}"#1〜4個のqを使用できます。

5
Isaac