我已经在 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
答案1
sudo su -
以复杂的书写方式sudo -i
,构建出质朴的环境。这就是登录 shell 的意义所在。即使是普通的也会sudo
从环境中删除大多数变量。此外sudo
还有一个外部命令;没有办法提升 shell 脚本本身的权限,只能以sudo
额外的权限运行外部程序 ( ),这意味着父 shell 中定义的任何 shell 变量(即非导出变量)和函数在孩子的外壳。
您可以通过不调用登录 shell(sudo bash
而不是sudo su -
或sudo -i
)并配置 sudo 让这些变量通过(在文件中Defaults !env_reset
或在文件Defaults env_keep=…
中sudoers
)来传递环境变量。这对您的函数没有帮助(尽管 bash 有函数导出工具,但 sudo 会阻止它)。
在子 shell 中获取函数的正常方法是在那里定义它们。注意引用:如果您使用<<EOF
here文档,则here文档的内容首先由父shell扩展,并且该扩展的结果成为子shell看到的脚本。也就是说,如果你写
sudo -u "$target_user" -i <<EOF
echo "$(whoami)"
EOF
这显示原始用户的名称,而不是目标用户的名称。为了避免第一阶段的扩展,请在运算符后面引用此处的文档标记<<
:
sudo -u "$target_user" -i <<'EOF'
echo "$(whoami)"
EOF
因此,如果您不需要将数据从父 shell 传递到子 shell,则可以使用此处引用的文档:
#!/bin/bash
sudo -u "$target_user" -i <<'EOF'
log_f() {
echo "LOG line: $@"
}
intVAR=$(date)
log_f "${intVAR}"
EOF
虽然您可以使用未加引号的此处文档标记将数据从父 shell 传递到子 shell,但这仅在数据不包含任何特殊字符时才有效。那是因为在像这样的脚本中
sudo -u "$target_user" -i <<EOF
echo "$(whoami)"
EOF
的输出whoami
变成了一些 shell 代码,而不是字符串。例如,如果whoami
命令返回"; rm -rf /; "true
,则子 shell 将执行该命令echo ""; rm -rf /; "true"
。
如果需要从父 shell 传递数据,一种简单的方法是将其作为参数传递。显式调用子 shell 并向其传递位置参数:
#!/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
以设置子 shell 的环境变量。
#!/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
,则必须显式读取它们,或者调用bash --login
而不是sh
.
答案2
这不起作用,因为该函数log_f
未在sudo su -
您启动的 shell 中声明。反而:
extVAR="yourName"
sudo su - <user> << EOF
log_f() {
echo "LOG line: $@"
}
intVAR=$(date)
log_f ${intVAR} ${extVAR}
EOF
您需要获取根子 shell 中定义的函数。这也许可以,但是……我不知道大部分东西是做什么的。至少——只要标准输入既不需要sudo
也不su
需要读取密码——就应该log_f()
声明这一点。
顺便说一句,我相信您的意思是将这些值扩展到根 shell 的输入中。如果您不想这样做,那么您应该引用EOF
和变量本身。
答案3
就我而言,我需要传入一个数组并遇到了一些麻烦,但在一段时间后通过将数组的值回显到 -keyenv
并将预期的代码包装在 中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[@]};
...