以 root 身份调用 bash 函数但给出 'unexpected end of file'
call a bash function as root but gives 'unexpected end of file'
为什么最后一个示例会抛出错误,而其他示例却能正常工作? Bash 在任何情况下都会被调用。
#!/bin/bash
function hello {
echo "Hello! user=$USER, uid=$UID, home=$HOME";
}
# Test that it works.
hello
# ok
bash -c "$(declare -f hello); hello"
# ok
sudo su $USER bash -c "$(declare -f hello); hello"
# error: bash: -c: line 1: syntax error: unexpected end of file
sudo -i -u $USER bash -c "$(declare -f hello); hello"
由于 -i
或 --login
开关而失败:
调试时好像是用-x
$ set -x
$ sudo -i -u $USER bash -c "$(declare -f hello); hello"
++ declare -f hello
+ sudo -i -u lea bash -c 'hello ()
{
echo "Hello! user=$USER, uid=$UID, home=$HOME"
}; hello'
现在如果手动执行它会导致同样的错误:
sudo -i -u lea bash -c 'hello ()
{
echo "Hello! user=$USER, uid=$UID, home=$HOME"
}; hello'
现在让我们做一个简单的小改动来让它工作:
sudo -i -u lea bash -c 'hello ()
{
echo "Hello! user=$USER, uid=$UID, home=$HOME";}; hello'
原因是 sudo -i
像交互式 shell 一样运行所有内容。这样做时,declare -f hello
中的每个换行符都会在内部变成 space。大括号代码块在同一行时需要在结束大括号之前有一个分号,declare -f funcname
不提供,因为它在新行中用结束大括号扩展函数源。
现在让这个行为变得非常简单:
$ sudo bash -c 'echo hello
echo world'
hello
world
它执行两个 echo
语句,因为它们由换行符分隔。
但是:
$ sudo -i bash -c 'echo hello
echo world'
hello echo world
它执行第一个 echo
语句,将所有内容打印为参数,因为换行符已被替换为 space。
It is the same code in all examples, so it should be ok.
是的,"$(declare -f hello); hello"
始终是相同的字符串。但是 sudo su
和 sudo -i
的处理方式不同,正如 发现的那样。
sudo -i
在将参数传递给 bash
之前引用它的参数。这个引用过程似乎没有记录并且非常糟糕。要查看实际执行的内容,您可以在 ~/.bash_profile/
:
中打印传递给 bash -c
的参数
~/.bash_profile
的内容
cat <<EOF
# is executed as
$BASH_EXECUTION_STRING
# resulting in output
EOF
一些 sudo -i
糟糕且不一致的引用示例
换行符被换行符
$ sudo -u $USER -i echo '1
2'
# is executed as
echo 1\
2
# resulting in output
12
引号转义为文字
$ sudo -u $USER -i echo \'single\' \"double\"
# is executed as
echo \'single\' \"double\"
# resulting in output
'single' "double"
但是$
没有被引用
$ sudo -u $USER -i echo $var
# is executed as
echo $var
# resulting in output
一些旁注:
您对su
的用法可能有误解。
sudo su $USER bash -c "some command"
不执行bash -c "echo 1; echo 2"
。 -c ...
由 su
解释并作为 -c ...
传递给 $USER
的默认值 shell。之后,剩余的参数也传递给 shell。执行的命令是
defaultShellOfUSER -c "some command" bash
你可能想写
sudo su -s bash -c "some command" "$USER"
交互式 shell 行为不同
su
只是执行-c
指定的命令。但是 sudo -i
开始登录 shell,在您的情况下,登录 shell 似乎是 bash(不一定是这种情况,请参见上一节)。
交互式 bash 会话的行为不同于 bash -c "..."
或 bash script.sh
。交互式 bash 源文件,如 .profile
、.bash_profile
,并启用历史扩展、别名等。有关完整列表,请参阅 bash 手册中的 Interactive Shell Behavior 部分。
为什么最后一个示例会抛出错误,而其他示例却能正常工作? Bash 在任何情况下都会被调用。
#!/bin/bash
function hello {
echo "Hello! user=$USER, uid=$UID, home=$HOME";
}
# Test that it works.
hello
# ok
bash -c "$(declare -f hello); hello"
# ok
sudo su $USER bash -c "$(declare -f hello); hello"
# error: bash: -c: line 1: syntax error: unexpected end of file
sudo -i -u $USER bash -c "$(declare -f hello); hello"
由于 -i
或 --login
开关而失败:
调试时好像是用-x
$ set -x
$ sudo -i -u $USER bash -c "$(declare -f hello); hello"
++ declare -f hello
+ sudo -i -u lea bash -c 'hello ()
{
echo "Hello! user=$USER, uid=$UID, home=$HOME"
}; hello'
现在如果手动执行它会导致同样的错误:
sudo -i -u lea bash -c 'hello ()
{
echo "Hello! user=$USER, uid=$UID, home=$HOME"
}; hello'
现在让我们做一个简单的小改动来让它工作:
sudo -i -u lea bash -c 'hello ()
{
echo "Hello! user=$USER, uid=$UID, home=$HOME";}; hello'
原因是 sudo -i
像交互式 shell 一样运行所有内容。这样做时,declare -f hello
中的每个换行符都会在内部变成 space。大括号代码块在同一行时需要在结束大括号之前有一个分号,declare -f funcname
不提供,因为它在新行中用结束大括号扩展函数源。
现在让这个行为变得非常简单:
$ sudo bash -c 'echo hello
echo world'
hello
world
它执行两个 echo
语句,因为它们由换行符分隔。
但是:
$ sudo -i bash -c 'echo hello
echo world'
hello echo world
它执行第一个 echo
语句,将所有内容打印为参数,因为换行符已被替换为 space。
It is the same code in all examples, so it should be ok.
是的,"$(declare -f hello); hello"
始终是相同的字符串。但是 sudo su
和 sudo -i
的处理方式不同,正如
sudo -i
在将参数传递给 bash
之前引用它的参数。这个引用过程似乎没有记录并且非常糟糕。要查看实际执行的内容,您可以在 ~/.bash_profile/
:
bash -c
的参数
~/.bash_profile
cat <<EOF
# is executed as
$BASH_EXECUTION_STRING
# resulting in output
EOF
一些 sudo -i
糟糕且不一致的引用示例
换行符被换行符
$ sudo -u $USER -i echo '1
2'
# is executed as
echo 1\
2
# resulting in output
12
引号转义为文字
$ sudo -u $USER -i echo \'single\' \"double\"
# is executed as
echo \'single\' \"double\"
# resulting in output
'single' "double"
但是$
没有被引用
$ sudo -u $USER -i echo $var
# is executed as
echo $var
# resulting in output
一些旁注:
您对su
的用法可能有误解。
sudo su $USER bash -c "some command"
不执行bash -c "echo 1; echo 2"
。 -c ...
由 su
解释并作为 -c ...
传递给 $USER
的默认值 shell。之后,剩余的参数也传递给 shell。执行的命令是
defaultShellOfUSER -c "some command" bash
你可能想写
sudo su -s bash -c "some command" "$USER"
交互式 shell 行为不同
su
只是执行-c
指定的命令。但是 sudo -i
开始登录 shell,在您的情况下,登录 shell 似乎是 bash(不一定是这种情况,请参见上一节)。
交互式 bash 会话的行为不同于 bash -c "..."
或 bash script.sh
。交互式 bash 源文件,如 .profile
、.bash_profile
,并启用历史扩展、别名等。有关完整列表,请参阅 bash 手册中的 Interactive Shell Behavior 部分。