Sudo ile bir bash fonksiyonunu nasıl çalıştırabilirim?


29

Çalışmak için kök ayrıcalıklarını gerektiren global bir bashrc'de tanımlanmış bir bash fonksiyonum var. Örneğin, sudo ile nasıl çalıştırabilirim sudo myfunction. Varsayılan olarak bir hata veriyor:

sudo: myfunction: komut bulunamadı


2
Hiç denemedim, ancak bu blog yazısı başa çıkacak
Grizly

Yukarıdaki betiğin kurulumu 'set alias sudo = sudowrap' gerektiriyor, ki bu imho'yu tavsiye etmiyor. Çalışması için hiçbir şey gerektirmeyen bir çözüm için lütfen cevabımı görün.
Luca Borrione

Bu, kabuk fonksiyonlarının kötü olmasının birçok nedeninden biridir. Shell işlevleri, ortamınızı değiştirmek istediğiniz komutlarla sınırlı olmalıdır. Gerisi için gerçek scriptleri kullanın. Bir fonksiyonun avantajı nedir? (Tamam, "Aşırı kullanım" kötüdür, kendi işlevlerini yerine getirmez. Bahse girerim daha pek çok iyi neden vardır. Ama senaryo yazarken kural değil, istisna
olmalılar

Yanıtlar:


4

Luca lütfen bana bu soruyu işaret etti, işte benim yaklaşımım: sudo çağrısından önce işlevi / takma adı genişletin ve sudo'ya tamamen iletin, geçici dosyalara gerek yoktur.

Açıklaması blogumda burada . Çok sayıda fiyat teklifi var :-)

# Wrap sudo to handle aliases and functions
# Wout.Mertens@gmail.com
#
# 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=0
    while getopts xVhlLvkKsHPSb:p:c:a:u: t; do
        if [ "$t" = x ]; then
            parse=true
        else
            opt[$i]="-$t"
            let i++
            if [ "$OPTARG" ]; then
                opt[$i]="$OPTARG"
                let i++
            fi
        fi
    done
    shift $(( $OPTIND - 1 ))
    if [ $# -ge 1 ]; then
        c="$1";
        shift;
        case $(type -t "$c") in 
        "")
            echo No such command "$c"
            return 127
            ;;
        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\""
            ;;
        esac
        if [ -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
            done
        else
            # Otherwise, quote the arguments. The echo gets an extra
            # space to prevent echo from parsing arguments like -n
            while [ -n "$1" ]; do
                t="${1//\'/\'\\\'\'}"
                c="$c '$t'"
                shift
            done
        fi
        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

Bu yaklaşımın tek dezavantajı, oradan referansta olduğunuz herhangi bir ekstra işlevi değil, yalnızca aradığınız işlevi genişletmesidir. Kyle'ın yaklaşımı, muhtemelen bashrc'nize yüklenen işlevlere ( bash -caramada yürütülmesi koşuluyla) referans veriyorsanız, bunu daha iyi ele alır .


ServerFault'da, harici siteye bağlamanın yanı sıra istenen kodu göstermesi tercih edilir, böylece kullanıcılar istedikleri bilgileri almak için tıklamaları gerekmez ve böylece bilgiler harici sitelerin potansiyel ölümünden kurtulur.
Göze çarpan derleyici,

15

Şunları yapabilirsiniz exportBir için kullanılabilir hale getirmek için işlev bash -calt kabukta veya kullanmak istediğiniz komut.

your_function () { echo 'Hello, World'; }
export -f your_function
bash -c 'your_function'

Düzenle

Bu, doğrudan alt kabuklar için işe yarar, ancak görünüşe göre sudoişlevleri iletmez (yalnızca değişkenler). Hatta çeşitli kombinasyonlarını kullanarak setenv, env_keepve inkâr env_resetyardım görünmüyor.

Düzenle 2

Ancak , şunlar anlaşılmaktadır su yapar destek verilen işlevlerin.

your_function () { echo 'Hello, World'; }
export -f your_function
su -c 'your_function'

2
+1, bunun doğru cevap olduğunu söyleyebilirim.
Kyle Brandt

1
Bu yöntemin işe yarayıp yaramadığı ?? Benim durumumda değil.
pradeepchhetri

@pradeepchhetri Tam olarak ne denediğiniz, hangi kabuğu kullandığınız ve hangi işletim sistemi kullandığınız gibi daha fazla bilgi vermek isteyebilirsiniz.
Legolas

@Legolas: Yukarıdaki komut dosyasında yazılan aynı şeyi yazmaya çalışıyorum. Ben hatayı alıyorum bash: your_function: command not found. Ben kullanıyorum Ubuntu 11.04ve bash shell.
pradeepchhetri

@pradeepchhetri ne kullanırsanız sudo -E bash -c 'your_function'?
Legolas

4

Belki yapabilirsin:

function meh() {
    sudo -v
    sudo cat /etc/shadow
}

Bu çalışmalı ve komut satırına sudo yazmaktan kurtarır.


1
Sisteminize bağlı olarak ... bu sudo komutunun her çağrısını parolayı girmeniz için ister ... veya bir kez sorar ve önbelleğe alır. Kök olarak çalışıp çalışmadığınızı tespit etmek daha iyi olurdu, ve değilse ... bash betiğini bir kez daha sudo ile tekrar arayın.
TheCompWiz

Sudo şifresini önbelleğe almayan bir sistemle henüz karşılaşmadım: timestamp_timeout için varsayılan değer 5'tir. 0'a ayarlarsanız, her zaman bir şifre girmeniz istenir, ancak bu özel bir ayar olacaktır.
wzzrd

3

Bir sudo bağlamında bir işlev çağırmanız gerekirse, kullanmak istiyorsanız declare:

#!/bin/bash

function hello() {
  echo "Hello, $USER"
}

sudo su another_user -c "$(declare -f hello); hello"

Bu, fonksiyonunuz başka bir fonksiyon çağırmazsa işe yarar.
modiX

Kullanım davam için bu en iyi cevap.
Jim

2

Sudo'nun kendisini çalıştıracağını söyleyerek yeni bir kabuk işletirdim, sonra işlev root yetkileriyle çalışacak. Örneğin, şöyle bir şey:

vim myFunction
#The following three lines go in myFunction file
function mywho {
    sudo whoami
}

sudo bash -c '. /home/kbrandt/myFunction; mywho'
root

Hatta o zaman hatta bir takma ad yapmak için gidebilirsiniz sudo bash.


2
#!/bin/bash

function smth() {
    echo "{{"
    whoami
    echo "}}"
}

if [ $(whoami) != "root" ]; then
    whoami
    echo "i'm not root"
    sudo $0
else
    smth
fi

2

Dennis Williamson’ın cevabının yorumlarında Legolas’ın da belirttiği gibi , yığılma akışında yayınlanan benzer bir sorudaki bülbüllerin cevabını okumalısınız .

Ondan başlayarak, temel olarak büllgeler fikrini idrak eden bu konuyu ele alacak bir fonksiyon yazdım.

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
# 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"
}



Kullanım örneği:
aşağıdaki pasajı çalıştırma

#!/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



Çıktı olacak

  1. sudo olmadan arama
    Merhaba adınız!
    Aşağıdaki paramları geçtiniz:
    ilk
    saniye

  2. sudo ile arama
    Merhaba kök!
    Aşağıdaki paragrafları geçtin:
    -n
    john bitti
    -s
    foo



Bunu, istediğiniz gibi bashrc dosyasında tanımlanmış bir işlevi çağıran bir kabukta kullanmanız gerekirse, önceki exesudo işlevini aynı bashrc dosyasına da koymalısınız :

function yourfunc ()
{
echo "Hello "$( whoami )"!"
}
export -f yourfunc

function exesudo ()
{
   # copy here
}
export -f exesudo



O zaman oturumu kapatıp tekrar giriş yapmalı veya kullanmalısınız.

source ~/.bashrc



Sonunda exesudo'yu aşağıdaki gibi kullanabilirsiniz:

$ yourfunc
Hello yourname!

$ exesudo yourfunc
Hello root!

Döner /dev/shm/22481: No such file or directory.
modiX
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.