2016-11-12 12 views
0

私はbashを学んでいます。そして、私は一時的なスクリプトファイルに別の関数をラップし、サブシェルでsudo -uコマンドで実行する関数を作りたいと思います。 私が遭遇した問題は、生成されたスクリプトがラップ関数でエクスポートされても、ラップされた関数を見つけることができないことです。 以下にテストコードを追加します。問題を見つけた人は、私に知らせてください。どうもありがとうございました。bashの関数で関数をどのようにエクスポートできますか?

main.sh

source "./display.sh" 
source "./sudo_wrap.sh" 

display_func "load success" 

sudo_wrap_func '' 'display_func' '3' '4 5' 

出力、display.sh、sudo_wrap.shおよび時間的ファイルを生成したが、以下に添付され、

出力

display_func : load success 
export -f display_func 
30481: line 5: display_func: command not found 

display.sh

function display_func() { 
    echo "display_func : [email protected]" 
} 

sudo_wrap.sh

function sudo_wrap_func() { 

    local sudo_user="${1:-root}" 
    local function_name="${2:?'function_name is null string.'}" 
    shift 2 
    local func_augs=("[email protected]") 

    local script 

    # *** script : header *** 
    script="#!/bin/bash\n" 
    script="${script}\n" 

    # *** script : making augments for function *** 
    script="${script}augs=(" 

    for aug in "${func_augs[@]}" 
    do 
    if [[ "${aug}" =~ [[:blank:]] ]]; then 
     script=" ${script} \"${aug}\"" 
    else 
     script=" ${script} ${aug}" 
    fi 
    done 
    script="${script})\n" 

    local tmp_script_file="${RANDOM}" 

    echo -e "${script}" >> "${tmp_script_file}" 

    # *** script : calling function with augments *** 

    echo -e "${function_name} \"\${augs[@]}\"\n" >> "${tmp_script_file}" 

    echo "export -f "${function_name}"" >&2 
    export -f "${function_name}" 

    sudo -u"${sudo_user}" bash "${tmp_script_file}" 
    rm "${tmp_script_file}" 

} 

一時的に生成されたファイル(この場合は、ファイル名は30481である)

#!/bin/bash 

augs=(3 "4 5") 

display_func "${augs[@]}" 
+2

かなり複雑に見えます。実際に何を達成しようとしていますか? – Robert

+0

'tempfile'コマンドをチェックして、tempレースを防ぐ。 – Robert

+0

@Robert:ありがとうございます。私がしたいのは、sudoコマンドで関数を実行することです。私はsudo some_functionを実行できません。だから私は別のスクリプトで関数をラップし、sudoコマンドで実行します。ところで、「temp race」とは何ですか?どうもありがとうございました。 – mora

答えて

2

私がコメントで言ったように、基本的な問題はsudoは(変数や関数の両方を含む)、その環境をきれいにということです別のユーザーとしてコマンド(/ script)を実行する前にこれはsudo -Eで上書きすることができますが、の場合にのみ、が/ etc/sudoersで明示的に許可されている場合のみです。

しかし問題は不溶性ではありません。その関数の定義をスクリプトに含めるだけで、その環境で再作成されます。 bashには便利なコマンドdeclare -f display_funcもあり、関数定義を適切な形式で出力します(そして、declare -p variableは変数に対しても同じことをします)。したがって、それらを使用して適切な定義をスクリプトに追加することができます。

これは私がこれを行うために書いたスクリプトです。スクリプトといくつかの変更を加えました。私は-u usernameを別のユーザーとして指定して実行します(別のユーザーを指定しない場合は、最初の引数として''を渡す必要はありません)。私はまた、-f functionname-v variablenameを追加して、追加の関数と変数定義をスクリプトに "エクスポート"します(main関数がそれらに依存する場合)。また、/ tmpに一時スクリプトファイルを作成し、必要に応じて所有権を変更して、他のユーザーが読むことができるようにします。ここで

#!/bin/bash 

me="$(basename "$0")" 
usage() { 
    echo "Usage: $me [-u user] [-f otherfunction] [-v variablename] function [args...]" >&2 
} 

tmp_script_file=$(mktemp "/tmp/${me}.XXXXXXXXXXXX") || { 
    echo "Error creating temporary script file" >&2 
    exit 1 
} 
echo "#!/bin/bash" > "$tmp_script_file" # Not actually needed, since we'll run it with "bash" 

# Parse the command options; "-u" gets stored for later, but "-f" and "-v" write 
# the relevant declarations to the script file as we go. 
sudo_user="" 
while getopts u:f:v: OPT; do 
    case "$OPT" in 
     u) 
     sudo_user="$OPTARG" ;; 

     f) 
     declare -f "$OPTARG" >>"$tmp_script_file" || { 
      echo "Error saving definition of function $OPTARG" >&2 
      exit 1 
     } ;; 

     v) 
     declare -p "$OPTARG" >>"$tmp_script_file" || { 
      echo "Error saving definition of variable $OPTARG" >&2 
      exit 1 
     } ;; 

     ?) usage; exit 1 ;; 
    esac 
done 
shift $(($OPTIND-1)) 

if (($# == 0)); then # No actual command specified 
    usage 
    exit 1 
fi 

# Write the main function itself into the script 
declare -f "$1" >>"$tmp_script_file" || { 
    echo "Error saving definition of function $1" >&2 
    exit 1 
} 

# Then the command to run it, with arguments quoted/escaped as 
# necessary. 
printf "%q " "[email protected]" >>"$tmp_script_file" 
# the printf above won't write a newline, so add it by hand 
echo >>"$tmp_script_file" 

# If the script will run as someone other than root, change ownership of the 
# script so the target user can read it 
if [[ -n "$sudo_user" ]]; then 
    sudo chown "$sudo_user" "$tmp_script_file" 
fi 

# Now launch the script, suitably sudo'ed 
sudo ${sudo_user:+ -u "$sudo_user"} bash "$tmp_script_file" 

# Clean up 
sudo rm "$tmp_script_file" 

は、それを使用しての例です:あなたはsourceでスクリプトを実行しているか、機能することが、それを行うことのいずれかによって、関数や変数をエクスポートする必要性を取り除くことができ

$ foo() { echo "foo_variable is '$foo_variable'"; } 
$ bar() { echo "Running the function bar as $(whoami)"; echo "Arguments: $*"; foo; } 
$ export -f foo bar # need to export these so the script can see them 
$ export foo_variable='Whee!!!' # ditto 
$ # Run the function directly first, so see what it does 
$ bar 1 2 3 
Running the function bar as gordon 
Arguments: 1 2 3 
foo_variable is 'Whee!!!' 
$ # Now run it as another user with the wrapper script 
$ ./sudo_wrap.sh -f foo -v foo_variable -u deenovo bar 1 2 3 
Running the function bar as deenovo 
Arguments: 1 2 3 
foo_variable is 'Whee!!!' 

注意$meがどのように定義されているかを変更する必要があります。usage関数は、すべてexitreturnsに置き換えて、私が考えなかったかもしれません。

+0

クール。これのユースケースは何ですか?具体的には、なぜスクリプトを動的に生成する必要がありますか?なぜ、単に既存のスクリプトを呼び出すのではなく(sudoの有無にかかわらず)? – Robert

+1

@Robert:スクリプトはsudoで簡単に実行できます。シェル関数はそうではありません。特定のユースケースが何であるかはわかりませんが、直接行うことはできません。 –

+0

@Robert:自分で機能を変更できる場合は、前述のchepnerのようにサブシェルで実行する別のスクリプトを作成せずにsudoを関数内に置く方が良いかもしれません。ところで、私は初心者のプログラマーです。だから、プログラミングデザインの観点からの私の状況は、他人には適用されないかもしれません。 – mora

関連する問題