Comment puis-je exécuter une fonction bash avec sudo?
29
J'ai une fonction bash définie dans un bashrc global, qui nécessite des privilèges root pour fonctionner. Comment puis-je l'exécuter avec sudo, par exemple sudo myfunction. Par défaut, cela donne une erreur:
l'installation du script ci-dessus nécessite 'set alias sudo = sudowrap', ce qui n'est pas recommandé à mon humble avis. Veuillez voir ma réponse pour une solution qui ne nécessite rien pour fonctionner.
Luca Borrione
C'est l'une des nombreuses raisons pour lesquelles les fonctions shell sont mauvaises. Les fonctions du shell doivent être limitées aux commandes que vous souhaitez modifier votre environnement. Utilisez des scripts réels pour le reste. Quel est l'avantage d'une fonction? (OK, la «surutilisation» est mauvaise, elle ne fonctionne pas elle-même. Et je parie qu'il y a beaucoup d'autres bonnes raisons. Mais elles devraient être l'exception, pas la règle, lors de l'écriture de scripts.)
Jeff Learman
Réponses:
4
Luca m'a gentiment pointé cette question, voici mon approche: Développez la fonction / alias avant l'appel à sudo et passez-la dans son intégralité à sudo, aucun fichier temporaire nécessaire.
Expliqué ici sur mon blog . Il y a beaucoup de gestion des devis :-)
# Wrap sudo to handle aliases and functions# [email protected]## Accepts -x as well as regular sudo options: this expands variables as you not root## Comments and improvements welcome## Installing: source this from your .bashrc and set alias sudo=sudowrap# You can also wrap it in a script that changes your terminal color, like so:# function setclr() {# local t=0 # SetTerminalStyle $1 # shift# "$@"# t=$?# SetTerminalStyle default# return $t# }# alias sudo="setclr sudo sudowrap"# If SetTerminalStyle is a program that interfaces with your terminal to set its# color.# Note: This script only handles one layer of aliases/functions.# If you prefer to call this function sudo, uncomment the following# line which will make sure it can be called that#typeset -f sudo >/dev/null && unset sudo
sudowrap (){local c="" t="" parse=""local-a opt
#parse sudo args
OPTIND=1
i=0while getopts xVhlLvkKsHPSb:p:c:a:u: t;doif["$t"= x ];then
parse=true
else
opt[$i]="-$t"
let i++if["$OPTARG"];then
opt[$i]="$OPTARG"
let i++fifidone
shift $(( $OPTIND -1))if[ $# -ge 1 ]; then
c="$1";
shift;case $(type -t "$c")in"")
echo No such command "$c"return127;;
alias)
c="$(type "$c")"# Strip "... is aliased to `...'"
c="${c#*\`}"
c="${c%\'}";;function)
c="$(type "$c")"# Strip first line
c="${c#* is a function}"
c="$c;\"$c\"";;*)
c="\"$c\"";;esacif[-n "$parse"];then# Quote the rest once, so it gets processed by bash.# Done this way so variables can get expanded.while[-n "$1"];do
c="$c \"$1\""
shift
doneelse# Otherwise, quote the arguments. The echo gets an extra# space to prevent echo from parsing arguments like -nwhile[-n "$1"];do
t="${1//\'/\'\\\'\'}"
c="$c '$t'"
shift
donefi
echo sudo "${opt[@]}"-- bash -xvc \""$c"\" >&2
command sudo "${opt[@]}" bash -xvc "$c"else
echo sudo "${opt[@]}">&2
command sudo "${opt[@]}"fi}# Allow sudowrap to be used in subshells
export -f sudowrap
Le seul inconvénient de cette approche est qu'elle ne fait qu'étendre la fonction que vous appelez, pas les fonctions supplémentaires auxquelles vous faites référence à partir de là. L'approche de Kyle gère probablement mieux cela si vous faites référence à des fonctions qui sont chargées dans votre bashrc (à condition qu'elle soit exécutée à l' bash -cappel).
Sur ServerFault, il est préférable d'afficher le code souhaité ainsi qu'un lien vers le site externe, afin que les utilisateurs n'aient pas à cliquer pour obtenir les informations qu'ils souhaitent, et ainsi les informations survivent à la mort potentielle de sites externes.
Compilateur remarquable
15
Vous pouvez exportvotre fonction pour le rendre disponible pour un bash -csous - shell ou des scripts dans lesquels vous souhaitez l'utiliser.
Cela fonctionne pour les sous-coquilles directes, mais sudone transmet apparemment pas les fonctions (uniquement les variables). Même en utilisant diverses combinaisons de setenv, env_keepet la négation env_resetne semblent pas à l' aide.
Modifier 2
Cependant , il semble que sucela prenne en charge les fonctions exportées.
si cette méthode fonctionne ?? Dans mon cas, ce n'est pas le cas.
pradeepchhetri
@pradeepchhetri Vous voudrez peut-être donner plus d'informations, telles que ce que vous essayez précisément, le shell que vous utilisez et le système d'exploitation que vous utilisez.
Legolas
@Legolas: J'essaie la même chose que le script écrit dans le script ci-dessus. Je reçois l'erreur bash: your_function: command not found. J'utilise Ubuntu 11.04et bash shell.
pradeepchhetri
@pradeepchhetri et si vous utilisez sudo -E bash -c 'your_function'?
Legolas
4
Vous pouvez peut-être faire:
function meh(){
sudo -v
sudo cat /etc/shadow
}
Cela devrait fonctionner et vous éviter de taper sudo sur la ligne de commande.
Selon votre système ... cela vous invitera à chaque appel de la commande sudo pour entrer le mot de passe ... ou vous invitera une fois et le mettra en cache. Il serait préférable de détecter si vous exécutez en tant que root, et sinon ... appelez à nouveau le script bash avec sudo une fois.
TheCompWiz du
Je n'ai pas encore rencontré de système qui ne cache pas le mot de passe sudo: la valeur par défaut pour timestamp_timeout est 5. Si vous le définissez sur 0, on vous demande toujours un mot de passe, mais ce serait un paramètre personnalisé.
wzzrd
3
Si vous devez appeler une fonction dans le contexte d'un sudo, vous souhaitez utiliser declare:
Cela fonctionne, tant que votre fonction n'appelle pas d'autres fonctions.
modiX
pour mon cas d'utilisation, c'est la meilleure réponse.
Jim
2
Je voudrais exécuter un nouveau shell en demandant à sudo d'exécuter le shell lui-même, puis la fonction s'exécutera avec les privilèges root. Par exemple quelque chose comme:
vim myFunction
#The following three lines go in myFunction filefunction mywho {
sudo whoami
}
sudo bash -c '. /home/kbrandt/myFunction; mywho'
root
Vous pouvez même alors créer un alias pour la sudo bashligne.
Comme l'a souligné Legolas dans les commentaires de la réponse de Dennis Williamson, vous devriez lire la réponse de bmargulies sur une question similaire publiée sur stackoverflow.
À partir de cela, j'ai écrit une fonction pour couvrir ce problème, qui réalise essentiellement l'idée de 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 2012function exesudo (){### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #### LOCAL VARIABLES:#### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #### I use underscores to remember it's been passedlocal _funcname_="$1"local params=("$@")## array containing all params passed herelocal tmpfile="/dev/shm/$RANDOM"## temporary filelocal filecontent ## content of the temporary filelocal regex ## regular expressionlocal 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[@]}"doif[["$param"=~ $regex ]]then
content="${content}\t\"${param}\"\n"else
content="${content}\t${param}\n"fidone
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"}
Exemple d'utilisation:
exécution de l'extrait de code suivant
#!/bin/bashfunction 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
Sortira
appeler sans sudo
Bonjour yourname!
Vous avez passé les paramètres suivants:
première
seconde
appeler avec sudo
Bonjour root!
Vous avez passé les paramètres suivants:
-n
john done
-s
foo
Si vous devez utiliser ceci dans un shell appelant une fonction définie dans votre bashrc, comme vous l'avez demandé, vous devez également placer la fonction exesudo précédente dans le même fichier bashrc , comme suit:
function yourfunc (){
echo "Hello "$( whoami )"!"}
export -f yourfunc
function exesudo (){# copy here}
export -f exesudo
Ensuite, vous devez vous déconnecter et vous reconnecter ou utiliser
Réponses:
Luca m'a gentiment pointé cette question, voici mon approche: Développez la fonction / alias avant l'appel à sudo et passez-la dans son intégralité à sudo, aucun fichier temporaire nécessaire.
Expliqué ici sur mon blog . Il y a beaucoup de gestion des devis :-)
Le seul inconvénient de cette approche est qu'elle ne fait qu'étendre la fonction que vous appelez, pas les fonctions supplémentaires auxquelles vous faites référence à partir de là. L'approche de Kyle gère probablement mieux cela si vous faites référence à des fonctions qui sont chargées dans votre bashrc (à condition qu'elle soit exécutée à l'
bash -c
appel).la source
Vous pouvez
export
votre fonction pour le rendre disponible pour unbash -c
sous - shell ou des scripts dans lesquels vous souhaitez l'utiliser.modifier
Cela fonctionne pour les sous-coquilles directes, mais
sudo
ne transmet apparemment pas les fonctions (uniquement les variables). Même en utilisant diverses combinaisons desetenv
,env_keep
et la négationenv_reset
ne semblent pas à l' aide.Modifier 2
Cependant , il semble que
su
cela prenne en charge les fonctions exportées.la source
bash: your_function: command not found
. J'utiliseUbuntu 11.04
etbash shell
.sudo -E bash -c 'your_function'
?Vous pouvez peut-être faire:
Cela devrait fonctionner et vous éviter de taper sudo sur la ligne de commande.
la source
Si vous devez appeler une fonction dans le contexte d'un sudo, vous souhaitez utiliser
declare
:la source
Je voudrais exécuter un nouveau shell en demandant à sudo d'exécuter le shell lui-même, puis la fonction s'exécutera avec les privilèges root. Par exemple quelque chose comme:
Vous pouvez même alors créer un alias pour la
sudo bash
ligne.la source
la source
Comme l'a souligné Legolas dans les commentaires de la réponse de Dennis Williamson, vous devriez lire la réponse de bmargulies sur une question similaire publiée sur stackoverflow.
À partir de cela, j'ai écrit une fonction pour couvrir ce problème, qui réalise essentiellement l'idée de bmargulies.
Exemple d'utilisation:
exécution de l'extrait de code suivant
Sortira
Si vous devez utiliser ceci dans un shell appelant une fonction définie dans votre bashrc, comme vous l'avez demandé, vous devez également placer la fonction exesudo précédente dans le même fichier bashrc , comme suit:
Ensuite, vous devez vous déconnecter et vous reconnecter ou utiliser
Enfin, vous pouvez utiliser exesudo comme suit:
la source
/dev/shm/22481: No such file or directory
.