我尝试导出函数,然后使用bash执行它,但不工作:如何使用sudo执行bash函数?
$ export -f my_func
$ sudo bash -c 'my_func'
bash: my_func: command not found
如果我尝试没有sudo使用bash运行功能(bash的-c“my_func,并将”),它的工作原理。
有什么想法?
我尝试导出函数,然后使用bash执行它,但不工作:如何使用sudo执行bash函数?
$ export -f my_func
$ sudo bash -c 'my_func'
bash: my_func: command not found
如果我尝试没有sudo使用bash运行功能(bash的-c“my_func,并将”),它的工作原理。
有什么想法?
从bmargulies的答案开始,我写了一个函数来解决这个问题,基本实现了他的想法。使用的
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
# EXESUDO
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
#
# Purpose:
# -------------------------------------------------------------------- #
# Execute a function with sudo
#
# Params:
# -------------------------------------------------------------------- #
# $1: string: name of the function to be executed with sudo
#
# Usage:
# -------------------------------------------------------------------- #
# exesudo "funcname" followed by any param
#
# -------------------------------------------------------------------- #
# Created 01 September 2012 Last Modified 02 September 2012
function exesudo()
{
### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ##
#
# LOCAL VARIABLES:
#
### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ##
#
# I use underscores to remember it's been passed
local _funcname_="$1"
local params=("[email protected]") ## array containing all params passed here
local tmpfile="/dev/shm/$RANDOM" ## temporary file
local filecontent ## content of the temporary file
local regex ## regular expression
local func ## function source
### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ##
#
# MAIN CODE:
#
### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ##
#
# WORKING ON PARAMS:
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# Shift the first param (which is the name of the function)
unset params[0] ## remove first element
# params=("${params[@]}") ## repack array
#
# WORKING ON THE TEMPORARY FILE:
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
content="#!/bin/bash\n\n"
#
# Write the params array
content="${content}params=(\n"
regex="\s+"
for param in "${params[@]}"
do
if [[ "$param" =~ $regex ]]
then
content="${content}\t\"${param}\"\n"
else
content="${content}\t${param}\n"
fi
done
content="$content)\n"
echo -e "$content" > "$tmpfile"
#
# Append the function source
echo "#$(type "$_funcname_")" >> "$tmpfile"
#
# Append the call to the function
echo -e "\n$_funcname_ \"\${params[@]}\"\n" >> "$tmpfile"
#
# DONE: EXECUTE THE TEMPORARY FILE WITH SUDO
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sudo bash "$tmpfile"
rm "$tmpfile"
}
实施例:
运行下面的代码片断
#!/bin/bash
function exesudo()
{
# copy here the previous exesudo function !!!
}
test_it_out()
{
local params=("[email protected]")
echo "Hello "$(whoami)"!"
echo "You passed the following params:"
printf "%s\n" "${params[@]}" ## print array
}
echo "1. calling without sudo"
test_it_out "first" "second"
echo ""
echo "2. calling with sudo"
exesudo test_it_out -n "john done" -s "done"
exit
威尔输出
不用sudo打电话
Hello yourname!
您通过以下PARAMS:
第一
第二调用使用sudo
您好根!
您通过以下PARAMS:
-n
约翰·多恩
-s
富
如果你需要使用这个在shell调用的函数,而在你的bashrc中定义,就像另一个用户在serverfault上提出类似的问题一样,那么你必须把以前的exesudo函数放在同一个的.bashrc文件,以及像如下:
function yourfunc()
{
echo "Hello "$(whoami)"!"
}
export -f yourfunc
function exesudo()
{
# copy here
}
export -f exesudo
然后,你必须注销并重新登录或使用
source ~/.bashrc
最后,你可以使用exesudo如下:
$ yourfunc
Hello yourname!
$ exesudo yourfunc
Hello root!
这是一项相当大的工作!做得好。顺便说一句,只有我修改的是sudo调用部分。我添加了退出代码传播,所以我可以在测试工具中使用漂亮的小函数。这是我的修改: 从这: $ sudo的庆典 “$ TMPFILE” $ RM “$ TMPFILE” 这样: $ sudo的庆典 “$ TMPFILE” $ EXIT_CODE = $? $ rm“$ tmpfile” $ return $ EXIT_CODE – LavaScornedOven 2013-10-16 15:13:23
这种感觉很神奇:/ – sleepycal 2014-11-02 14:20:58
难道你不能用'{echo'#!/ bin/bash'生成临时文件吗?声明-f“$ 1”|头-n -1 | tail -n +3); }>“$ tmpfile”',而不是将参数打包到脚本中,而是将它们作为sudo的一部分传递给它?它会将身体缩小至5条线 – jbo5112 2017-05-18 18:31:19
每次运行sudo时,它都会分叉并执行shell的新副本,并以root用户身份运行。该shell不会从你的shell继承函数(它不能),也不会继承以前执行的函数。你将不得不写出一个包含函数定义和调用的文件,并请求调用该文件。
不仅它不能,它可能永远不会那样做,由于安全原因。 – 2012-02-25 23:14:07
Runnig bash本身也会执行bash的新副本,但它仍然能够从父shell中继承函数。 另外,sudo在某种程度上能够保留导出的bash变量,所以我认为可能会有一些技巧对函数做同样的事情。 据我所知,这可能有一些安全原因,但如果我使用sudo在更受限制的用户下运行功能会怎么样? – Miroslav 2012-02-26 01:27:49
变量遍历过程环境机制。功能没有这样的事情。 – bmargulies 2012-02-26 01:56:41
简而言之,简单不具有在其单引号的东西,这对我的作品:
export code='
function whoAmI() {
echo `whoami`
}
whoAmI
'
sudo bash -c "$code"
# output: root
你可以做,使用declare -f
,如下面的例子:
function ttt() {
whoami
echo First parameter is $1
}
ttt dd
DECL=`declare -f ttt`
sudo bash -c "$DECL; ttt asd"
与调用你的函数替代sudo只是在你的函数中调用“sudo”调用。例如,我想在OS X中设置一个快捷方式来将localhost转发到特定的端口。
function portforward() {
echo "y" | sudo ipfw flush;
sudo ipfw add 100 fwd 127.0.0.1,$1 tcp from any to any 80 in;
echo "Forwarding localhost to port $1!";
}
函数命中sudo并要求输入密码。 (然后管道“y”到ipfw的提示,不涉及这个问题)。之后,sudo被缓存,所以该函数的其余部分无需输入密码即可执行。
从本质上讲,这只是运行像:
portforward 8000
Password:
Forwarding localhost to port 8000!
,填补我的需要,因为我只需要输入一次密码,它采取的照顾。虽然如果第一次输入密码失败,会有点难看。用于检测第一个sudo是否成功的额外点以及否则退出该函数。
所有你需要做的是检查,如果你是根,如果是,运行功能,如果不是,则调用使用sudo的脚本:
#!/bin/bash
# script name: 'foo.sh'
function foo(){
whoami
}
DIR=$(cd "$(dirname "$0")" && pwd) # get script dir
if [ "$UID" -ne 0 ]; then # check if you are root
sudo $DIR/foo.sh # NOT: run script with sudo
else
foo # YES: run function
fi
为什么你需要运行这样的说法? – 2012-02-25 23:20:47
因为整个脚本通过标准输入传送到bash。它可能来自卷曲或猫.. – Miroslav 2012-02-26 01:33:16
SF上的同一个问题:http://serverfault.com/questions/177699/how-can-i-execute-a-bash-function-with-sudo/ – 2012-03-31 08:59:48