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
変更したときに出力されます。b
b
Namerefは、サブシェルを使用せずに関数から値を抽出するのに役立ちます$(addfoo)
。