親シェルで子シェルの変数を使用可能にする方法

親シェルで子シェルの変数を使用可能にする方法

Webサービスでいくつかのレポートの時間を測定するための迅速で簡単なスクリプトを作成しました。

BASE_URL='http://example.com/json/webservice/'
FIRST=1
FINAL=10000

for report_code in $(seq 1 $FINAL); do
  (time -p response=$(curl --write-out %{http_code} --silent -O ${BASE_URL}/${report_code}) ) 2> ${report_code}.time

  echo $response  # <------- this is out of scope!  How do I fix that?
  if [[ $response = '404' ]]; then
    echo "Deleting report # ${report_code}!"
    rm ${report_code}
  else
    echo "${report_code} seems to be good!"
  fi
done

time出力をリダイレクトするには、サブシェルでコマンドをラップする必要がありますが、これにより親$responseシェルで値が使用できなくなります。この問題をどのように解決できますか?

答え1

エラーが発生しやすいマーシャリングや面倒な通信がなければ、サブシェルから親シェルに変数値を渡す方法はありません。

幸い、ここではサブシェルは必要ありません。リダイレクトには次のものだけが必要です。コマンドのグループ化を使用すると{ … }サブシェルではありません。

{ time -p response=$(curl --write-out '%{http_code}' --silent -O "${BASE_URL}/${report_code}"); } 2> "${report_code}.time"

(忘れないで変数の置換は二重引用符で囲まれています。.)

答え2

同僚のU&Lユーザー:main()Cスタイル関数の使用に対する私の答えに反対する前に、次のリンクにアクセスしてください。https://unix.stackexchange.com/a/313561/85039スクリプトで主な機能を使用することは、その分野の多くの専門家が使用する一般的な方法です。


Gillesが指摘したように、サブシェルは環境外で変数を使用できないようにすることはできません。しかし、これを別の角度からアプローチしてみましょう。関数にスクリプトを作成すると、変数を宣言してlocal編集できます。

Bash 4.3のマニュアルでlocal説明:

...localが関数内で使用される場合、変数名はその関数とそのサブ関数にのみ表示されます。

例:

#!/bin/bash

outter()
{
    for i in $(seq 1 3)
    do
        var=$i
    done
}

main()
{
    local var=0
    outter
    echo $var
}
main "$@"
$ ./testscript.sh                                                                                                        
3

ご覧のとおり、ループ関数が3回繰り返された後に変数が変更されます。

答え3

aで変数をリダイレクトtest.txtし、親シェルからインポートできます。

testfn()
{
echo "test" > test.txt # redirect your variable in a test.txt
}

testfn &       # execute your function in the subshell

testresult=$(cat test.txt) # get your variable in the parent shell
printf '%s\n' "$testresult"

答え4

bash 4.3からできます名前参照変数

#!/usr/bin/env bash

# outvar is a nameref variable that allows us to set the value of a variable 
# outside our scope
addfoo() {
   local x="$1"
   local -n outvar=$2

   x="foo$x"

   outvar="$x"
}

declare b=“loll”

addfoo "bar" b

echo "$b”

これはfoobar、関数が範囲外でも変数をaddfoo変更したときに出力されます。bb

Namerefは、サブシェルを使用せずに関数から値を抽出するのに役立ちます$(addfoo)

関連情報