Bash/kshで関数と変数を宣言しました。それらをSudo su - {user} << EOF
に転送する必要があります。
#!/bin/bash
log_f() {
echo "LOG line: $@"
}
extVAR="yourName"
Sudo su - <user> << EOF
intVAR=$(date)
log_f ${intVAR} ${extVAR}
EOF
Sudo su -
は、Sudo -i
を記述するための複雑な方法であり、手付かずの環境を構築します。それがログインシェルのポイントです。単純なSudo
でも、ほとんどの変数を環境から削除します。さらに、Sudo
は外部コマンドです。シェルスクリプト自体で特権を昇格する方法はありません。追加の特権で外部プログラム(Sudo
)を実行するだけです。これは、親シェルで定義されたシェル変数(つまり、エクスポートされない変数)と関数を意味します子シェルでは使用できません。
ログインシェル(Sudo bash
またはSudo su -
の代わりにSudo -i
)を呼び出さずにSudoを構成して環境変数を渡すことができます(sudoers
ファイルでDefaults !env_reset
またはDefaults env_keep=…
を使用)。これは関数の助けにはなりません(bashには関数エクスポート機能がありますが、Sudoはそれをブロックします)。
子シェルで関数を取得する通常の方法は、関数をそこで定義することです。引用に注意してください。ヒアドキュメントに<<EOF
を使用する場合、ヒアドキュメントの内容は最初に親シェルによって展開され、その展開の結果が子シェルに表示されるスクリプトになります。つまり、あなたが書く場合
Sudo -u "$target_user" -i <<EOF
echo "$(whoami)"
EOF
これにより、ターゲットユーザーではなく、元のユーザーの名前が表示されます。この展開の最初のフェーズを回避するには、<<
演算子の後にhereドキュメントマーカーを引用します。
Sudo -u "$target_user" -i <<'EOF'
echo "$(whoami)"
EOF
したがって、親シェルから子シェルにデータを渡す必要がない場合は、引用符で囲まれたヒアドキュメントを使用できます。
#!/bin/bash
Sudo -u "$target_user" -i <<'EOF'
log_f() {
echo "LOG line: $@"
}
intVAR=$(date)
log_f "${intVAR}"
EOF
引用符で囲まれていないhereドキュメントマーカーを使用して、親シェルから子シェルにデータを渡すことができますが、これは、データに特殊文字が含まれていない場合にのみ機能します。それは、次のようなスクリプトで
Sudo -u "$target_user" -i <<EOF
echo "$(whoami)"
EOF
whoami
の出力は、文字列ではなく、シェルコードのビットになります。たとえば、whoami
コマンドが"; rm -rf /; "true
を返した場合、子シェルはコマンドecho ""; rm -rf /; "true"
を実行します。
親シェルからデータを渡す必要がある場合、簡単な方法はそれを引数として渡すことです。子シェルを明示的に呼び出して、位置パラメーターを渡します。
#!/bin/bash
extVAR="yourName"
Sudo -u "$target_user" -i sh _ "$extVAR" <<'EOF'
log_f() {
echo "LOG line: $@"
}
intVAR=$(date)
log_f "${intVAR}" "${1}"
EOF
渡す変数が複数ある場合、名前で渡す方が読みやすくなります。子シェルの環境変数を設定するには、env
を明示的に呼び出します。
#!/bin/bash
extVAR="yourName"
Sudo -u "$target_user" -i env extVAR="$extVAR" sh <<'EOF'
log_f() {
echo "LOG line: $@"
}
intVAR=$(date)
log_f "${intVAR}" "${1}"
EOF
/etc/profile
とターゲットユーザーの~/.profile
が読み取られると予想した場合は、それらを明示的に読み取るか、sh
ではなくbash --login
を呼び出す必要があります。
私の場合、配列を渡す必要があり、いくつかの問題がありましたが、しばらくして配列の値をenv
- keyにエコーし、目的のコードを_bash -c '<intended code>'
_でラップすることで成功しました。配列を再作成します(例:: INNER_KEY=($<env_key>)
)。
たとえば:
_#!/usr/bin/env bash
PLUGINS=(foo bar baz)
Sudo -u <some-user> -i env PLUGINS="`echo ${PLUGINS[@]}`" sh <<'EOF'
bash -c '
FOO=($PLUGINS);
echo values: \[${FOO[@]}\];
for pl in ${FOO[@]};
do echo value: $pl;
done;
'
EOF
_
問題は、次のようなことを直接実行できないことでした(_bash -c '...'
_を使用しない):
_FOO=($PLUGINS);
for pl in ${FOO[@]};
...
_
起動した_log_f
_シェルで関数_Sudo su -
_が宣言されていないため、これは機能しません。代わりに:
_extVAR="yourName"
Sudo su - <user> << EOF
log_f() {
echo "LOG line: $@"
}
intVAR=$(date)
log_f ${intVAR} ${extVAR}
EOF
_
ルートサブシェルで定義された関数を取得する必要があります。それでうまくいくかもしれませんが、ほとんどのことはわかりません。少なくとも-Sudo
もsu
もパスワードを読み取るためにstdinを必要としない限り-log_f()
を宣言する必要があります。
ところで、これらの値をルートシェルの入力に展開するつもりだと思います。そうするつもりがない場合は、EOF
と変数自体を引用する必要があります。