Eu tenho uma função bash definida em um bashrc global, que requer privilégios de root para funcionar. Como posso executá-lo com o sudo, por exemplo sudo myfunction. Por padrão, ele fornece um erro:
a instalação do script acima requer 'set alias sudo = sudowrap', que não é recomendável imho. Por favor, veja minha resposta para uma solução que não requer nada para funcionar.
Luca Borrione 2/12/12
Essa é uma das muitas razões pelas quais as funções de shell são más. As funções do shell devem ser limitadas aos comandos que você deseja alterar seu ambiente. Use scripts reais para o resto. Qual é a vantagem de uma função? (OK, "O uso excessivo" é mau, não funciona por si só. E aposto que existem muitas outras boas razões. Mas elas devem ser a exceção, e não a regra, ao escrever scripts.)
Jeff Learman
Respostas:
4
Luca gentilmente me apontou para esta pergunta, eis a minha abordagem: expanda a função / alias antes da chamada para o sudo e passe-a completamente para o sudo, sem necessidade de arquivos temporários.
Explicado aqui no meu blog . Há um monte de manipulação de cotações :-)
# 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
A única desvantagem dessa abordagem é que ela apenas expande a função que você está chamando, e não as funções extras que você está referenciando a partir daí. A abordagem de Kyle provavelmente lida com isso melhor se você estiver referenciando funções que são carregadas no seu bashrc (desde que sejam executadas na bash -cchamada).
No ServerFault, é preferível que você mostre o código desejado e o link para o site externo, para que os usuários não precisem clicar para obter as informações desejadas, para que as informações sobrevivam à morte potencial de sites externos.
Compilador conspícuo
15
Você pode exportsua função para disponibilizá-lo para um bash -csubshell ou scripts nos quais deseja usá-lo.
Isso funciona para subshells diretos, mas aparentemente sudonão encaminha funções (apenas variáveis). Mesmo usando várias combinações de setenv, env_keepe negando env_resetparecem não ajuda.
Editar 2
No entanto , parece que suele suporta funções exportadas.
@pradeepchhetri Você pode fornecer mais informações, como o que está tentando com precisão, qual shell você usa e qual sistema operacional você usa.
precisa
@ Legolas: Eu estou tentando a mesma coisa que o script escreveu no script acima. Estou recebendo o erro bash: your_function: command not found. Eu estou usando Ubuntu 11.04e bash shell.
26612 pradeepchhetri
@pradeepchhetri what if you use sudo -E bash -c 'your_function'?
Legolas
4
Talvez você possa fazer:
function meh(){
sudo -v
sudo cat /etc/shadow
}
Isso deve funcionar e evita que você digite sudo na linha de comando.
Dependendo do seu sistema ... isso solicitará que cada chamada do comando sudo insira a senha ... ou solicite uma vez e armazene em cache. Seria melhor detectar se você está executando como root e, se não estiver ... chame o script bash novamente com o sudo uma vez.
TheCompWiz
Ainda não encontrei um sistema que não armazene em cache a senha do sudo: o padrão para timestamp_timeout é 5. Se você configurá-lo como 0, sempre será solicitada uma senha, mas essa seria uma configuração personalizada.
Wzzrd
3
Se você precisar chamar uma função no contexto de um sudo, você deseja usar declare:
Como apontado por Legolas nos comentários da resposta de Dennis Williamson, você deve ler a resposta de bmargulies em uma pergunta semelhante postada no stackoverflow.
A partir disso, escrevi uma função para cobrir esta questão, que basicamente realiza a ideia 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"}
Exemplo de uso:
executando o seguinte snippet
#!/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
Saída
chamando sem sudo
Olá, seu nome!
Você passou os seguintes parâmetros:
primeiro
segundo
chamando com sudo
Olá root!
Você passou os seguintes parâmetros:
-n
john done
-s
foo
Se você precisar usá-lo em um shell que chame uma função definida em seu bashrc, conforme solicitado, será necessário colocar a função exesudo anterior no mesmo arquivo bashrc , como o seguinte:
function yourfunc (){
echo "Hello "$( whoami )"!"}
export -f yourfunc
function exesudo (){# copy here}
export -f exesudo
Então você precisa sair e fazer login novamente ou usar
source ~/.bashrc
Finalmente, você pode usar o exesudo da seguinte maneira:
Respostas:
Luca gentilmente me apontou para esta pergunta, eis a minha abordagem: expanda a função / alias antes da chamada para o sudo e passe-a completamente para o sudo, sem necessidade de arquivos temporários.
Explicado aqui no meu blog . Há um monte de manipulação de cotações :-)
A única desvantagem dessa abordagem é que ela apenas expande a função que você está chamando, e não as funções extras que você está referenciando a partir daí. A abordagem de Kyle provavelmente lida com isso melhor se você estiver referenciando funções que são carregadas no seu bashrc (desde que sejam executadas na
bash -c
chamada).fonte
Você pode
export
sua função para disponibilizá-lo para umbash -c
subshell ou scripts nos quais deseja usá-lo.Editar
Isso funciona para subshells diretos, mas aparentemente
sudo
não encaminha funções (apenas variáveis). Mesmo usando várias combinações desetenv
,env_keep
e negandoenv_reset
parecem não ajuda.Editar 2
No entanto , parece que
su
ele suporta funções exportadas.fonte
bash: your_function: command not found
. Eu estou usandoUbuntu 11.04
ebash shell
.sudo -E bash -c 'your_function'
?Talvez você possa fazer:
Isso deve funcionar e evita que você digite sudo na linha de comando.
fonte
Se você precisar chamar uma função no contexto de um sudo, você deseja usar
declare
:fonte
Eu executaria um novo shell fazendo o sudo executar o próprio shell, então a função será executada com privilégios de root. Por exemplo, algo como:
Você poderia, então, criar um alias para a
sudo bash
linha também.fonte
fonte
Como apontado por Legolas nos comentários da resposta de Dennis Williamson, você deve ler a resposta de bmargulies em uma pergunta semelhante postada no stackoverflow.
A partir disso, escrevi uma função para cobrir esta questão, que basicamente realiza a ideia de bmargulies.
Exemplo de uso:
executando o seguinte snippet
Saída
Se você precisar usá-lo em um shell que chame uma função definida em seu bashrc, conforme solicitado, será necessário colocar a função exesudo anterior no mesmo arquivo bashrc , como o seguinte:
Então você precisa sair e fazer login novamente ou usar
Finalmente, você pode usar o exesudo da seguinte maneira:
fonte
/dev/shm/22481: No such file or directory
.