Tengo una función bash definida en un bashrc global, que requiere privilegios de root para funcionar. ¿Cómo puedo ejecutarlo con sudo sudo myfunction? Por defecto da un error:
la instalación del script anterior requiere 'set alias sudo = sudowrap', lo cual no es recomendable en mi humilde opinión. Vea mi respuesta para una solución que no requiere nada para funcionar.
Luca Borrione
Esta es una de las muchas razones por las que las funciones de shell son malas. Las funciones de Shell deben limitarse a los comandos que desea cambiar su entorno. Use guiones reales para el resto. ¿Cuál es la ventaja de una función? (OK, "El uso excesivo" es malo, no funciona por sí mismo. Y apuesto a que hay muchas otras buenas razones. Pero deberían ser la excepción, no la regla, al escribir guiones).
Jeff Learman
Respuestas:
4
Luca amablemente me señaló esta pregunta, aquí está mi enfoque: expanda la función / alias antes de la llamada a sudo y páselo en su totalidad a sudo, no se necesitan archivos temporales.
Explicado aquí en mi blog . Hay un montón de manejo de cotizaciones :-)
# 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
La única desventaja de este enfoque es que solo expande la función que está llamando, no las funciones adicionales a las que hace referencia desde allí. El enfoque de Kyle probablemente lo maneja mejor si hace referencia a funciones que están cargadas en su bashrc (siempre que se ejecute en la bash -cllamada).
En ServerFault, es preferible que muestre el código que desea y que se vincule al sitio externo, para que los usuarios no tengan que hacer clic para obtener la información que desean, y así la información sobrevive a la posible muerte de sitios externos.
Compilador conspicuo el
15
Puede hacer que exportsu función esté disponible para una bash -csubshell o scripts en los que desea usarlo.
Esto funciona para subcapas directas, pero aparentemente sudono reenvía funciones (solo variables). Incluso usar varias combinaciones de setenv, env_keepy negar env_reset, no parecen ayudar.
Editar 2
Sin embargo , parece que sulo hace de soporte exportados funciones.
@pradeepchhetri Es posible que desee proporcionar más información, como lo que está intentando con precisión, qué shell utiliza y qué sistema operativo utiliza.
Legolas
@Legolas: Estoy intentando lo mismo que el script escrito en el script anterior. Estoy consiguiendo el error bash: your_function: command not found. Estoy usando Ubuntu 11.04y bash shell.
pradeepchhetri
@pradeepchhetri ¿y si lo usas sudo -E bash -c 'your_function'?
Legolas
4
Quizás puedas hacer:
function meh(){
sudo -v
sudo cat /etc/shadow
}
Esto debería funcionar y le ahorra escribir sudo en la línea de comandos.
Dependiendo de su sistema ... esto le pedirá cada llamada del comando sudo para ingresar la contraseña ... o le pedirá una vez y guardarla en caché. Sería mejor detectar si está ejecutando como root, y si no ... llame al script bash nuevamente con sudo una vez.
TheCompWiz
Todavía tengo que encontrar un sistema que no guarde en caché la contraseña de sudo: el valor predeterminado para timestamp_timeout es 5. Si lo configura en 0, siempre se le solicita una contraseña, pero esa sería una configuración personalizada.
wzzrd
3
Si necesita llamar a una función en el contexto de un sudo, desea usar declare:
Como señaló Legolas en los comentarios de la respuesta de Dennis Williamson , debe leer la respuesta de bmargulies en una pregunta similar publicada en stackoverflow.
A partir de eso, escribí una función para cubrir este problema, que básicamente se da cuenta de la idea 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"}
Ejemplo de uso:
ejecutar el siguiente fragmento
#!/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
Saldrá
llamando sin sudo
Hola tu nombre!
Pasaste los siguientes parámetros:
primer
segundo
llamando con sudo
Hola root!
Pasaste los siguientes parámetros:
-n
john done
-s
foo
Si necesita utilizar esto en una cáscara de llamar a una función que se define en su bashrc, como lo pidió, entonces usted tiene que poner la función exesudo anterior sobre el mismo bashrc archivo, así, como la siguiente:
function yourfunc (){
echo "Hello "$( whoami )"!"}
export -f yourfunc
function exesudo (){# copy here}
export -f exesudo
Luego debe cerrar sesión e iniciar sesión nuevamente o usar
source ~/.bashrc
Finalmente puedes usar exesudo de la siguiente manera:
Respuestas:
Luca amablemente me señaló esta pregunta, aquí está mi enfoque: expanda la función / alias antes de la llamada a sudo y páselo en su totalidad a sudo, no se necesitan archivos temporales.
Explicado aquí en mi blog . Hay un montón de manejo de cotizaciones :-)
La única desventaja de este enfoque es que solo expande la función que está llamando, no las funciones adicionales a las que hace referencia desde allí. El enfoque de Kyle probablemente lo maneja mejor si hace referencia a funciones que están cargadas en su bashrc (siempre que se ejecute en la
bash -c
llamada).fuente
Puede hacer que
export
su función esté disponible para unabash -c
subshell o scripts en los que desea usarlo.Editar
Esto funciona para subcapas directas, pero aparentemente
sudo
no reenvía funciones (solo variables). Incluso usar varias combinaciones desetenv
,env_keep
y negarenv_reset
, no parecen ayudar.Editar 2
Sin embargo , parece que
su
lo hace de soporte exportados funciones.fuente
bash: your_function: command not found
. Estoy usandoUbuntu 11.04
ybash shell
.sudo -E bash -c 'your_function'
?Quizás puedas hacer:
Esto debería funcionar y le ahorra escribir sudo en la línea de comandos.
fuente
Si necesita llamar a una función en el contexto de un sudo, desea usar
declare
:fuente
Ejecutaría un nuevo shell haciendo que sudo ejecute el propio shell, luego la función se ejecutará con privilegios de root. Por ejemplo algo como:
Incluso podría ir a hacer un alias para la
sudo bash
línea también.fuente
fuente
Como señaló Legolas en los comentarios de la respuesta de Dennis Williamson , debe leer la respuesta de bmargulies en una pregunta similar publicada en stackoverflow.
A partir de eso, escribí una función para cubrir este problema, que básicamente se da cuenta de la idea de bmargulies.
Ejemplo de uso:
ejecutar el siguiente fragmento
Saldrá
Si necesita utilizar esto en una cáscara de llamar a una función que se define en su bashrc, como lo pidió, entonces usted tiene que poner la función exesudo anterior sobre el mismo bashrc archivo, así, como la siguiente:
Luego debe cerrar sesión e iniciar sesión nuevamente o usar
Finalmente puedes usar exesudo de la siguiente manera:
fuente
/dev/shm/22481: No such file or directory
.