Bashは引用および/またはエスケープされた文字列変数を単語に拡張できますか?

Bashは引用および/またはエスケープされた文字列変数を単語に拡張できますか?

bash次の文字列を含むシェル変数があります。性格スペースで区切られます。文字列には、単語内のエスケープスペースなどのエスケープ文字を含めることができます。スペースを含む単語も引用できます。

$FOO代わりに、引用符なしで使用されたシェル変数は複数の単語になりますが、"$FOO"元の文字列の引用符とエスケープは効果がありません。

引用符とエスケープ文字を考慮して文字列を単語に分割する方法は?

背景

サーバーは、クライアントに提供されているコマンドラインに関係なく、スクリプトへのアクセスを制限するためにファイルにsshオプションForceCommandを提供します。sshd_configssh

スクリプトは、続行する前に変数(クライアントに提供されるコマンドラインをSSH_ORIGINAL_COMMAND含む文字列)を使用して引数リストを設定します。だからユーザーはsshssh

$ ssh some_server foo 'bar car' baz

スクリプトが実行されていることを確認し、スクリプトが実行されるとSSH_ORIGINAL_COMMAND4つのパラメータに設定されます。foo bar car baz

set -- ${SSH_ORIGINAL_COMMAND}

望む結果ではありません。したがって、ユーザーは再試行します。

$ ssh some_server foo bar\ car baz

同じ結果 - クライアントシェルがこれを表示するには、2番目のパラメータのバックスラッシュをエスケープする必要がありますssh。これらはどうですか?

$ ssh some_server foo 'bar\ car' baz
$ ssh some_server foo bar\\ car baz

どちらも有効です。printf "%q"参照ラッパークライアント参照を簡素化できます。

クライアントの引用を使用すると、適切に引用された文字列がサーバーに送信され、sshサーバーから受信したSSH_ORIGINAL_COMMANDバックスラッシュがそのまま残りますfoo bar\ car baz

setしかし、引用やエスケープを考慮していないため、まだ問題があります。解決策があります:

eval set -- ${SSH_ORIGINAL_COMMAND}

しかし、これは許容できません。考える

$ ssh some_server \; /bin/sh -i

非常に不満:eval入力制御が不足しているため使用できません。

eval実行部分のない文字列拡張機能が必要です。

ベストアンサー1

使用read:

read -a ssh_args <<< "${SSH_ORIGINAL_COMMAND}"
set -- "${ssh_args[@]}"

これは単語をSSH_ORIGINAL_COMMAND配列に解析しssh_args\バックスラッシュ()をエスケープ文字として扱います。これにより、配列要素がパラメータとして提供されますsetssh次のように渡されたパラメータのリストで機能します。

$ ssh some_server foo 'bar\ car' baz
$ ssh some_server foo bar\\ car baz

printf "%q"はSSHラッパーを表します。以下は許可されています。

$ sshwrap some_server foo bar\ car baz
$ sshwrap some_server foo 'bar car' baz

以下は、これらのラッパーの例です。

#!/bin/bash
h=$1; shift
QUOTE_ARGS=''
for ARG in "$@"
do
  ARG=$(printf "%q" "$ARG")
  QUOTE_ARGS="${QUOTE_ARGS} $ARG"
done
ssh "$h" "${QUOTE_ARGS}"

おすすめ記事