web-dev-qa-db-ja.com

関数と変数をSudo su-<user> << EOFに転送する

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
9
waldauf

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[@]};
...
_
1
johanmynhardt

起動した_log_f_シェルで関数_Sudo su -_が宣言されていないため、これは機能しません。代わりに:

_extVAR="yourName"

Sudo su - <user> << EOF

log_f() {
echo "LOG line: $@"
}

  intVAR=$(date)
  log_f ${intVAR} ${extVAR}
EOF
_

ルートサブシェルで定義された関数を取得する必要があります。それでうまくいくかもしれませんが、ほとんどのことはわかりません。少なくとも-Sudosuもパスワードを読み取るためにstdinを必要としない限り-log_f()を宣言する必要があります。

ところで、これらの値をルートシェルの入力に展開するつもりだと思います。そうするつもりがない場合は、EOFと変数自体を引用する必要があります。

1
mikeserv