bashで関数を「エクスポート」できますか?


81
source some_file

some_file:

doit ()
{
  echo doit $1
}
export TEST=true

some_fileをソースとする場合、コマンドラインで関数「doit」と変数TESTを使用できます。ただし、このスクリプトの実行:

script.sh:

#/bin/sh
echo $TEST
doit test2

TESTの値を返しますが、不明な関数「doit」に関するエラーを生成します。

関数も「エクスポート」できますか、それともscript.shでsome_fileをソースにして、そこで関数を使用する必要がありますか?


2
変更:以下の答えを(質問が示すようenzotibは、あなたbashを使用することができると仮定すると、正しい)まとめ#!/bin/sh#!/bin/bashし、後に doit() {...}ちょうどexport -f doit
マイケル・

記録のために:このソリューションは通常#!/bin/sh、使用しても機能しますが#!/bin/bash、デフォルトのシェルがbashでない場合に問題を回避するために使用することをお勧めします。
ナゲル14

回答:


120

Bashでは、関数定義をサブシェルにエクスポートできます。

export -f function_name

たとえば、次の簡単な例を試すことができます。

./script1

    #!/bin/bash

    myfun() {
        echo "Hello!"
    }

    export -f myfun
    ./script2

./script2

    #!/bin/bash

    myfun

その後、呼び出す./script1と、出力Hello!が表示されます


16

を使用して関数を「エクスポート」するとexport -f、関数本体で環境変数が作成されます。この例を考えてみましょう:

$ fn(){ echo \'\"\ \ \$; }
$ export -f fn
$ sh -c printenv\ fn
() {  echo \'\"\ \ \$
}

これは、シェル(Bashだけ?)のみが関数を受け入れることができることを意味します。Bashはenvvarsをfunctionで始まると見なすだけなので、自分で関数を設定することもでき() {ます。

$ fn2='() { echo Hi;}' sh -c fn2
Hi
$ fn3='() {' sh -c :
sh: fn3: line 1: syntax error: unexpected end of file
sh: error importing function definition for `fn3'

この変数をSSH経由で「エクスポート」する必要がある場合、文字列としての機能が本当に必要です。これは、組み込みの-p関数(-f)の印刷オプション()で実行できますdeclare

$ declare -pf fn
fn () 
{ 
    echo \'\"\ \ \$
}

これは、SSHを介して実行する必要があるより複雑なコードがある場合に非常に便利です。次の架空のスクリプトを検討してください。

#!/bin/bash
remote_main() {
   local dest="$HOME/destination"

   tar xzv -C "$dest"
   chgrp -R www-data "$dest"
   # Ensure that newly written files have the 'www-data' group too
   find "$dest" -type d -exec chmod g+s {} \;
}
tar cz files/ | ssh user@host "$(declare -pf remote_main); remote_main"

fn2='() { echo Hi;}' sh -c fn2私にはうまくいきませんでした。アーチLinux上でsh私が得たのbash v5.0.7いますsh: fn2: command not foundshダッシュボードv0.2.3を使用してUbuntuで取得しましたsh: 1: fn2: not found。どのshシェルを使用しましたか?
ソコウィ

あなたの答えは間違っていると思います。f(){ echo a;}; export -f f; echo "$f"; sh -c 'printenv f; echo "$f"'私には何も印刷しないので、明らかにfプレーンな文字列としてエクスポートされません。上記の両方の組み合わせでテストしました。
ソコウィ

そして、関数が文字列としてエクスポートされたとしても、なぜshその文字列を関数として実行する必要があるのでしょうか?あなたの例でfn2='() { echo Hi;}' sh -c fn2は、fn2与えられたコマンドsh は文字通り文字列"fn2"です。shPATHでそのようなコマンドを検索する必要がありますが、変数があるかどうかを調べて、その変数$fn2を展開し、その値を関数として実行するべきでありません。編集:それだと思います!表示された動作は、ShellShock / Bashdoorとして知られるセキュリティバグでしたか?
ソコウィ

Bash 5.0.7(Arch Linux)では、プレフィックスが追加されているようです。これは、ShellShockに対応して行われた可能性があります。例:fn(){ echo foo; }; export -f fn; env | grep foo出力BASH_FUNC_fn%%=() { echo foo
Lekensteyn

7

上の建物Lekensteynの答え@ ...

使用declare -pfすると、現在のシェルで以前に定義されたすべての関数がSTDOUTに出力されます。

その時点で、STDOUTを任意の場所にリダイレクトし、事実上、以前に定義した関数を任意の場所に詰めることができます。

次の答えは、変数にそれらを詰め込みます。次に、その変数に加えて、新しいユーザーとして生成された新しいシェルに実行する関数の呼び出しをエコーし​​ます。これを行うにsudoは、-u(aka。user)スイッチを使用し、単純にBashを実行します(実行する入力としてパイプされたSTDOUTを受け取ります)。

BashシェルからBashシェルに移行することを知っているので、Bashは以前のシェルで定義された関数を正しく解釈することがわかります。同じバージョンの1つのBashシェルから同じバージョンの新しいBashシェルに移動する限り、構文は問題ないはずです。

異なるシェル間または異なるバージョンのBashがあるシステム間を移動する場合はYMMV。

#!/bin/bash
foo() {
  echo "hello from `whoami`"
}

FUNCTIONS=`declare -pf`; echo "$FUNCTIONS ; foo" | sudo -u otheruser bash
# $./test.sh
# hello from otheruser

5

関数をエクスポートすることはできませんが、記述している方法ではエクスポートできません。シェルは~/.bashrc、対話型シェルの開始時にのみファイルをロードします(bashのマンページで「呼び出し」を検索します)。

できることは、プログラムを起動したときにロードされる「ライブラリ」を作成することです。

source "$HOME/lib/somefile"

そして、非インタラクティブな機能と設定をそこに配置します。


そのため、「〜/ .profileを解析するために」「login」パラメータを使用してサブシェルを起動するか、そのファイルを取得する必要があります。
ニルス

もう少し詳しく見てみると、非対話型のシェルでは、既に持っているBASH_ENV環境変数を設定することができsome_file、呼び出されます。それを見つけるのは十分に簡単でしょう:echo echo foobar > /tmp/foobar; BASH_ENV=/tmp/foobar $SHELL -c :
アルセージュ

2

eval "$(declare -F | sed -e 's/-f /-fx /')"すべての機能をエクスポートます。

スクリプトでインタラクティブシェルを開始する前に、これを何度も実行して、関数と変数を使用しながらスクリプトコンテキストでデバッグおよび作業できるようにします。

例:

eval "$(declare -F | sed -e 's/-f /-fx /')"
export SOME IMPORTANT VARIABLES AND PASSWORDS
bash -i

1

関数はサブプロセスにエクスポートされません。これが.kshrcまたは.bashrcという名前のファイルがある理由です。サブシェルでも使用できる関数を定義するため。

スクリプトを実行する場合、。* shrcスクリプトは通常ソースされません。のように、明示的にコーディングする必要があります. ~/.kshrc


スクリプトはルートとして実行されるため、私の場合は〜root / .bashrcがオプションになります。そのヒントをありがとう。
ニルス

。* shrcファイルを使用している場合、彼らは(愚かなエイリアスのようなインタラクティブな動作を強制いけないことを確認することrm=rm -i
KTF

0

さて、私はLinuxが初めてですが、これを試すことができます。いくつかのファイルで、関数を作成する 'tmp / general'と呼びましょう:

func1(){
   echo "func from general"
}

シェルスクリプトに以下を追加します。

. /tmp/general

そして実行:

func1

画面が表示されますfunc from general


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.