関数をエクスポートしてから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=( "$@" ) ## array containing all params passed here
local tmpfile="/dev/shm/$RANDOM" ## temporary file
local content ## content of the temporary file
local regex ## regular expression
### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ##
#
# 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
出力されます
須藤なしで呼び出す
君の名は。
次のパラメータを渡しました:
最初
秒須藤との通話
こんにちはルート!
次のパラメータを渡しました:
-n
ジョン・ダン
-s
foo
bashrcで定義されている関数を呼び出すシェルでこれを使用する必要がある場合は、別のユーザーから serverfault で同様の質問があり、前のユーザーを配置する必要があります。次のように、同じbashrcファイルのexesudo関数も同様です。
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を実行するたびに、rootとして実行されているシェルの新しいコピーをフォークして実行します。そのシェルはシェルから関数を継承せず(継承できません)、以前の実行から関数を継承しません。関数の定義と呼び出し、およびその呼び出しを含むファイルを書き出す必要があります。
次の例のように、declare -f
を使用してこれを行うことができます。
function myfunc() {
whoami
echo First parameter is $1
}
myfunc foo
DECL=`declare -f myfunc`
Sudo bash -c "$DECL; myfunc bar"
Sudoを使用して関数を呼び出す代わりに、関数内で「Sudo」呼び出しを移動することもできます。たとえば、ローカルホストを特定のポートに転送するためのショートカット機能をOSXに設定したいと考えていました。
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!
また、パスワードを入力する必要があるのは1回だけで、パスワードが処理されるため、ニーズが満たされます。初めてパスワードを入力しなかった場合は少し醜いですが。最初のSudoが成功したかどうかを検出し、成功しなかった場合は関数を終了するための追加のポイント。
一重引用符が含まれていない短くて単純なものの場合、これは私にとってはうまくいきます:
export code='
function whoAmI() {
echo `whoami`
}
whoAmI
'
Sudo bash -c "$code"
# output: root
関数が.bashrcにある場合
次に、Sudo -i myfunc
あなたがしなければならないのはあなたが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