我尝试导出该函数,然后使用bash执行它,但这不起作用:
$ export -f my_func
$ sudo bash -c 'my_func'
bash: my_func: command not found
如果我尝试使用没有sudo的bash运行该函数(bash -c'my_func'),它就可以运行。
有什么想法吗?
答案 0 :(得分:16)
每次运行sudo时,它都会以root用户身份运行并执行shell的新副本。该shell不会从shell继承函数(它不能)并且它不会继承先前执行的函数。你必须写出一个包含函数定义和调用的文件,然后调用它。
答案 1 :(得分:14)
从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=( "$@" ) ## 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=( "$@" )
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的情况下打电话 你好你的名字!
您通过了以下参数:
第一
第二
- 醇>
用sudo打电话 你好根!
您通过了以下参数:
-n
约翰完成了 -s
FOO
如果你需要在一个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!
答案 2 :(得分:10)
您可以使用declare -f
执行此操作,如以下示例所示:
function myfunc() {
whoami
echo First parameter is $1
}
myfunc foo
DECL=`declare -f myfunc`
sudo bash -c "$DECL; myfunc bar"
答案 3 :(得分:3)
使用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是否成功的额外点,如果没有则退出该函数。
答案 4 :(得分:1)
对于没有单引号的简短而简单的东西,这对我有用:
export code='
function whoAmI() {
echo `whoami`
}
whoAmI
'
sudo bash -c "$code"
# output: root
答案 5 :(得分:0)
你所要做的就是检查你是否是root用户,如果是,运行该函数,如果没有,用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
答案 6 :(得分:0)
如果您的函数位于.bashrc中
然后就做
import requests
requests.get(url, data=formData)
答案 7 :(得分:0)
我花了几个月的时间来创建这个功能。完全透明,除了添加一个额外的参数外,它与真正的 sudo 命令具有相同的行为:
有必要先创建以下函数:
cmdnames () {
{ printf '%s' "$PATH" | xargs -d: -I{} -- find -L {} -maxdepth 1 -executable -type f -printf '%P\n' 2>/dev/null; compgen -b; } | sort -b | uniq
return 0
}
完全由我自己创建的函数如下:
sudo () {
local flagc=1
local flag=1
local i
if [[ $# -eq 1 && ( $1 == "-h" || ( --help == $1* && ${#1} -ge 4 ) ) ]]; then
command sudo "$@" | perl -lpe '$_ .= "\n -c, --run-command\t\trun command instead of the function if the names match" if /^ -C, / && ++$i == 1'
return ${PIPESTATUS[0]}
fi
for (( i=1; i<=$#; i++ )); do
if [[ ${!i} == --r ]]; then
command sudo "$@" 2>&1 | perl -lpe '$_ .= " '"'"'--run-command'"'"'" if /^sudo: option '"'"'--r'"'"' is ambiguous/ && ++$i == 1'
return ${PIPESTATUS[0]}
fi
if [[ ${!i} == -c || ( --run-command == ${!i}* && $(expr length "${!i}") -ge 4 ) ]]; then
flag=2
set -- "${@:1:i-1}" "${@:i+1}"
i=$((i-1))
continue
fi
command sudo 2>&1 | grep -E -- "\[${!i} [A-Za-z]+\]" > /dev/null && { i=$((i+1)); continue; }
cmdnames | grep "^${!i}$" > /dev/null && flagc=0
if [[ $flagc -eq 0 && $flag -eq 2 ]]; then break; fi
if declare -f -- "${!i}" &> /dev/null; then
flag=0
break
else
if [[ $flagc -eq 0 ]]; then break; fi
fi
done
if [[ $flag -eq 0 ]]; then
command sudo "${@:1:i-1}" bash -sc "shopt -s expand_aliases extglob; $(alias); $(declare -f); $(printf "%q " "${@:i}")"
else
command sudo "$@"
fi
return $?
}
缺点:无。