为什么最后一个例子抛出错误,而其他的工作?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
变成内部空间。当在同一行时,花括号代码块在结束花括号前需要一个分号,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
语句打印一切作为参数,因为换行符已经被空间所取代。
在所有示例中都是相同的代码,所以应该没问题。
是的,"$(declare -f hello); hello"
总是相同的字符串。但Lea Gris发现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"
doesnotexecutebash -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手册中的交互式Shell行为一节。