関数戻り値

関数戻り値

my_var=$(my_func arg1 arg2 ..)コード例を見ると、bash関数の戻り値が常に関数に反映され、次に使用される理由を誰かが説明できますか?

my_func ()
   {
   echo "$1 , $2, $3"
   }

my_var=$(my_func .. .. ..);

これを使用する代わりに、サブシェルは開かれません。

declare g_RV  #-- global return value for all functions

myfunc ()
   {
   g_RV="$1 , $2, $3"
   }

myfunc .. .. ..; my_var=$g_RV;

なぜなら、私は2番目の方法を使用していて、場合によっては最初の方法で失敗するのだろうかと思います。誰もがサブシェルを開いているので理由があります。

編集: KusalanandaとPaul_Pedantのコメントのおかげで、
$ 1ディレクトリ内のすべてのファイルを一覧表示するか、$ 2 INT> 0の場合は、再帰的にg_RV - LAF関数を使用して再帰関数呼び出しを追加し、
関数内で別の関数を呼び出します。と関数参照!

declare g_RV

shopt -s dotglob nullglob

#-- Recursive call with g_RV
#---------------------------
#-- call: LAF [directory STR] [recursive INT (>0 .. true, 0 .. false)]  ... List all files in a folder or inclusive all files in subfolders (recursive
LAF ()
   {
   local file files="" dir_path=$1
   if [[ ${dir_path:0:1} != "/" ]]; then dir_path=$(readlink -f "$dir_path"); fi
   
   for file in "$dir_path/"*; do
      if [[ -d $file ]]; then (($2)) && { LAF "$file"; files+=$g_RV; }                    #-- recursive call
      else files+="${file}"$'\n'; fi
      done
   g_RV=$files
   }
   
LAF "/tmp" 1; my_var1=$g_RV; echo "$my_var1";

#-- function calling other functions with g_RV
#---------------------------------------------
sum_A ()
   { 
   g_RV=$(($1+$2))
   }

sum_B()
   {
   g_RV=$(($1+$2))
   }

sum_C ()
   {
   local -i sum=0;
   sum_A 5 6; sum+=$g_RV
   sum_B 12 18; sum+=$g_RV
   g_RV=$sum
   }
  
sum_C; my_var2=$g_RV; echo "sum: $my_var2";

答え1

標準ツールとユーティリティは、次の方法で情報を返します。標準出力、終了状態(0 = 正常、そうでない場合はエラー)に結果を限定します。同じ一貫した方法で使用できるように、関数は同じことを行う必要があります。

あなたの例は、すべての関数から返された単一のグローバル変数を示しています。このアプローチを使用すると、複雑さが追加され、読みやすさが低下しない限り、パイプや文字列に関数を挿入することはできません。

考える

f() { sed 's/^/> /'; }
g() { nl; }

echo try | f | g    # "     1  > try"

各関数の戻り値にグローバル変数がある場合(または両方の関数に同じグローバル変数がある場合)、同じ効果を得るにはフープを超える必要があります。

シェルを実行していてすべてのオーバーヘッドを考慮すると、子プロセスの数はあまり関係ありません。速度が必要な場合は、シェルスクリプトを作成しないでください。

答え2

グローバル変数の使用は通常再利用できません。他の場所で使用されるグローバル変数と名前の競合がある可能性があります。

さらに、これはほとんどの人が機能が機能することを期待する標準的な方法ではありません。

答え3

  • 少ないコード
  • 読みやすい
  • 従来の方法はエラーが発生する可能性が低い。
  • echo計算コストがほぼゼロの組み込み関数です。
  • BashはBourne Again SHellです。いいえ[クラシック]プログラミング言語
  • 仕事をする古典的な方法は弾力的ですsource/.。つまり、何があっても常に動作するという意味です。

答え4

そうではないいつもただします。実際、あなたはあなたの質問に別の方法で答えました!

シェル関数は、実際には0から255の間の整数に制限されている終了状態を除いて何も返すことができないため、あまり役に立ちません。その後、外部変数を使用するか、必要なデータを印刷して出力をキャプチャするオプションがあります。

出力の印刷とキャプチャに問題がないわけではありません。コマンドの置き換えにより、ほとんどのシェルが経験するパフォーマンスの問題を無視しても、出力が構造化されていない単一の文字列またはバイトストリームであるという問題があります。 zsh以外のシェルでは、コマンド置換はNULバイトをキャプチャできないため、8ビットクリーンバイトストリームでもありません。

配列を返す必要がある場合は、外部変数を使用する方がはるかに簡単です。固定名の変数を使用する代わりにnamerefsを使用すると、呼び出し元は戻り値の変数名を渡すことができます。

たとえば、適切な配列がないと処理が困難ないくつかの値を持つ愚かな例は次のとおりです。

#!/bin/bash
funnystrings() {
    declare -n _dst="$1"
    _dst[0]="foo bar"
    _dst[1]="*"
    _dst[2]=$'new\nline'
}

a=()
funnystrings a
declare -p a

同様に、入力変数に別の変数名を渡す必要がある場合:

squares() {
    declare -n _src="$1" _dst="$2"
    local _i _val
    for _i in "${!_src[@]}"; do
        _val=${src[$i]}
        _dst[$i]=$(( _val * _val ))
    done
}
a=(1 2 3)
b=()
squares a b

これはBashでも実際には機能するかもしれませんがab特にsquares a bシェル間でネストされたローカル変数がどのように機能するかに奇妙なことがあるかもしれません。どんな試合のためにunset

関連情報