毎回インポートすることなく、このスクリプトファイルの機能をどのようにロードできますか? 「コマンドが見つかりません」(基本/スクリプト基本)

毎回インポートすることなく、このスクリプトファイルの機能をどのようにロードできますか? 「コマンドが見つかりません」(基本/スクリプト基本)

毎回インポートすることなく、このスクリプトファイルの機能をどのようにロードできますか?

foo実行したいスクリプト機能を含むファイルを作成しました。 PATHにあります/usr/bin

文書金持ち:

#!/bin/bash
echo "Running foo"

function x {
    echo "x"
}

xただし、端末に関数名を入力すると、次のようになります。
x: command not found

入力すると、foo次のよう
Running fooに表示されます(したがってファイルはPATHにあり、実行可能です)。

一度入力すると、実行機能をsource foo入力できますxx

私も知っている、これは非常に基本的な質問です。私はスクリプトを抽象化して管理しやすくしたいと思います(すべてを.profileまたは.bashrcにダンプするのと比較して)。

ベストアンサー1

問題は、.../binディレクトリ内のスクリプトがexec別のシェル環境で編集されたことです。その環境は実行後も持続しないため、完了時に定義はx() { ... ; }現在のシェル環境では持続しません。

. ./somescript.sh (またはsourceなどの一部のシェルで)bashzsh現在のシェルはスクリプトを現在の環境に読み込み、プロンプトで発行されたかのように内容を実行します。これはx() { ... ; }現在、シェル環境である対話型シェルで定義されています。

デフォルトでは、問題は次のように証明できます。

sh <<\HEREDOC_CMD_FILE #runs sh shell with heredoc input file
    { #begins current shell compound expression
        ( #begins subshell compound expression
            x() { echo 'I am function x.' ; } #define function x
            x #x invoked in subshell
        ) #ends subshell compound expression
        x #x invoked in current shell
    } #ends current shell compound expression
#v_end_v
HEREDOC_CMD_FILE

###OUTPUT###
I am function x.
sh: line 6: x: command not found

同様に( : subshell )、上記の例で定義された環境は完了後も維持されず、実行するスクリプトで定義された環境も維持されません。同様にsh、読み込み時にHEREDOC_CMD_FILEユーザーと同じ機能を実行し、source ../file現在のシェル実行環境でコンテンツを実行します。ただし、その環境はそれを実行したプロンプトを発行したシェルのサブシェルサブであるため、その環境では何も実行されません。そこでも。しかし、次のようにすることができます。

. /dev/fd/0 <<\HEREDOC_CMD_FILE && x
    x() { echo 'I am function x.' ; }
HEREDOC_CMD_FILE

###OUTPUT###
I am function x.

...これはあなたがやっていることとほぼ同じです。source ${script}ただし、ここでは.dotディスクにあるファイルの内容をインポートするのに対しstdin、あなたはディスクにあるファイルの内容をインポートします。

ただし、実行スクリプトと実行スクリプトの主な違いは、( : subshell )実行スクリプトの実行環境がどのように見えるかです。スクリプトを実行すると新しいオペレーティング環境 - したがって、コマンドラインから明示的にエクスポートまたは宣言しない限り、現在シェルで宣言されているすべての変数はその環境に転送されません。この動作は次のように説明できます。

{   x() { printf "$FMT" "$0" "$var2" x ; } #describe env
    export FMT='argv0: %s\t\tvar2: %s\t\tI am function %s.\n' \
        var1=val1 #var1 and FMT are explicitly exported
    var2=shell_val2 #var2 is not
    cat >./script && #read out stdin to >./script
        chmod +x ./script && #then make ./script executable
        var3=val3 ./script #then define var3 for ./script's env and execute
} <<\SCRIPT ; x ; y #send heredoc to block's stdin then call {x,y}()
#!/usr/bin/sh
#read out by cat to >./script then executed in a separate environment
y() { printf "$FMT" "$0" "$var2" y ; } #describe env
echo "${var1:-#var1 is unset or null}" #$var1 if not unset or null else :-this} 
echo "${var2:-#var2 is unset or null}"
echo "${var3:-#var3 is unset or null}"
export var2=script_val2
x ; y #run x() ; y() in script
#v_end_v                                                                                                                                                                                          
SCRIPT

###OUTPUT###
val1
#var2 is unset or null
val3
./script: line 8: x: command not found
argv0: ./script         var2: script_val2               I am function y.
argv0: sh               var2: shell_val2                I am function x.
sh: line 18: y: command not found

この動作は、プロンプトで実行するか、現在のシェルの子として実行するのとは異なります。つまり( : subshells )、上記のように実行中の子は明示的に編集する必要がありますが、親の環境を自動的に継承するということですexport

var1=val1 ; export var2=val2
x() { echo 'I am function x.' ; }
( 
    printf '%s\n' "$var1" "$var2" 
    x
)

###OUTPUT###
val1
val2
I am function x.

.dot最後に注目したいのは、現在のシェルで実行されているように、実行中のスクリプトに関数定義を含むファイルをインポートせず、親シェルで実行されたスクリプトに関数をエクスポートする移植可能な方法がないことです。デフォルトでは、変数を使用しているかのように移植することsourceはできません。しかし、実行中のスクリプトにexport functionあなたがいる可能性があると思います。もちろん、サブ環境(実行しているかどうかにかかわらず)はサブ環境と共に消えます。export fn_def='fn() { : fn body ; }'eval "$fn_def"

したがって、スクリプトで定義された関数が欲しいがスクリプト自体をインポートしたくない場合は、関数をいくつかのコマンドとその出力に読み込む必要がありますeval

eval "$(cat ./script)"

しかし、本質的に同じです. ./script。それはあまり効率的ではありません。ただ受け取れます。

これを行う最善の方法は、スクリプト自体から関数定義を削除し、独自のファイルに入れてから、必要に応じてスクリプトと現在のシェルの両方からインポートすることです。このように:

{
    echo 'x() { echo "I am function x and my argv0 is ${0}." ; }' >./fn_x                                                                                                                                                         
    echo '. ./fn_x ; x' >./script                                                                                                                                                                                                 
    chmod +x ./script && ./script                                                                                                                                                                                                 
    . ./fn_x ; x                                                                                                                                                                                                                  
}
###OUTPUT###
I am function x and my argv0 is ./script.
I am function x and my argv0 is sh.

対話型シェルで常に使用できるようにするには、. /path/to/fn_xシェルENVファイルに追加します。たとえば、にある関数を含むスクリプトの場合は、次のbash行を次に追加します。foo/usr/bin~/.bashrc

. /usr/bin/foo

起動時に何らかの理由でその場所でスクリプトを使用できない場合、シェルは期待どおりにENVファイルの残りの部分を読み取ってインポートしますが、stderr関数定義ファイルのインポートに問題があることを知らせる診断メッセージを印刷します。

おすすめ記事