web-dev-qa-db-ja.com

親シェルでサブシェルの変数を使用できるようにする方法

私は、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の値が親シェルで使用できなくなります。この問題を回避するにはどうすればよいですか?

10
iconoclast

変数の値をサブシェルからその親にもたらすことはできません。エラーが発生しやすいマーシャリングと面倒な通信を行わなければ、それができません。

幸い、ここにはサブシェルは必要ありません。リダイレクトに必要なのは コマンドのグループ化{ … }、サブシェルではありません。

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

(忘れないでください 変数置換を囲む二重引用符 。)

仲間の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回繰り返した後にわかるように、変数は変更されています。

4