-
22-08-2019 - |
質問
えていただきたいと思いることが可能に引数を渡すにはスクリプト機能により参考:
すなわちいるようになりますのC++:
void boo(int &myint) { myint = 5; }
int main() {
int t = 4;
printf("%d\n", t); // t->4
boo(t);
printf("%d\n", t); // t->5
}
そのためにBASHいようなもの:
function boo ()
{
var1=$1 # now var1 is global to the script but using it outside
# this function makes me lose encapsulation
local var2=$1 # so i should use a local variable ... but how to pass it back?
var2='new' # only changes the local copy
#$1='new' this is wrong of course ...
# ${!1}='new' # can i somehow use indirect reference?
}
# call boo
SOME_VAR='old'
echo $SOME_VAR # -> old
boo "$SOME_VAR"
echo $SOME_VAR # -> new
意思によりお願い申し上げます。
解決
この2018年には、この質問に値する。少なくともBash、Bash4.3-アルファを使用でき namerefs 通関数の引数により参考:
function boo()
{
local -n ref=$1
ref='new'
}
SOME_VAR='old'
echo $SOME_VAR # -> old
boo SOME_VAR
echo $SOME_VAR # -> new
の重要な点は:
の変数の名前を、ブは、その値:
boo SOME_VAR
, ないboo $SOME_VAR
.内部の機能を利用
local -n ref=$1
を宣言すること nameref のという名前の変数による$1
, とを意味なので参考に$1
もすることによるものであり、可変 名前$1
持つSOME_VAR
ます。この値の右側のように文字列(英字の大文字と小文字のネーミングは既存の変数:などのように文字列を取得しいlocal -n ref="my_var"
またはlocal -n ref=$(get_var_name)
います。declare
でも交換local
にコンテキストで許可を必要とする。見 の章ではシェルのパラメータをドリファレンスマニュアル ます。
このアプローチの利点は楽-)より読みやすさ、そして何よりも回避 eval
, は、安全保障の欠点を多数も記載されています。●
他のヒント
バッシュマン・ページ(パラメータ展開)から:
If the first character of parameter is an exclamation point (!), a level of variable indirection is introduced. Bash uses the value of the variable formed from the rest of parameter as the name of the variable; this variable is then expanded and that value is used in the rest of the substitution, rather than the value of parameter itself. This is known as indirect expansion.
そのための参照は、変数の名前です。ここで使用してswap
関数であります
一時変数を必要としない変数間接ます:
function swap()
{ #
# @param VARNAME1 VARNAME2
#
eval "$1=${!2} $2=${!1}"
}
$ a=1 b=2
$ swap a b
$ echo $a $b
2 1
ヘルパー関数upvar
を使用します:
# Assign variable one scope above the caller.
# Usage: local "$1" && upvar $1 value [value ...]
# Param: $1 Variable name to assign value to
# Param: $* Value(s) to assign. If multiple values, an array is
# assigned, otherwise a single value is assigned.
# NOTE: For assigning multiple variables, use 'upvars'. Do NOT
# use multiple 'upvar' calls, since one 'upvar' call might
# reassign a variable to be used by another 'upvar' call.
# See: http://fvue.nl/wiki/Bash:_Passing_variables_by_reference
upvar() {
if unset -v "$1"; then # Unset & validate varname
if (( $# == 2 )); then
eval $1=\"\$2\" # Return single value
else
eval $1=\(\"\${@:2}\"\) # Return array
fi
fi
}
そしてNewfun()
内からこのようにそれを使用します:
local "$1" && upvar $1 new
は、複数の変数を返すために、別のヘルパー関数upvars
を使用しています。これは、1つのupvar
コールが別の後続upvar
呼び出しで使用される変数を変更する場合が可能競合を回避する一回のコール内の複数の変数を渡すことができます。
を参照してください: http://www.fvue.nl/wiki/Bash:_Passing_variables_by_referenceヘルパー関数upvars
、より多くの情報のため。
に問題:
eval $1=new
$1
コマンドが含まれているために発生した場合、それは安全ではないということです。
set -- 'ls /;true'
eval $1=new # Oops
printf -v
を使う方が良いでしょう。
printf -v "$1" %s new
しかしprintf -v
配列を割り当てることはできません。
eval
宣言するために発生した場合、また、printf
とlocal
の両方が動作しません
g() { local b; eval $1=bar; } # WRONG
g b # Conflicts with `local b'
echo $b # b is empty unexpected
競合がlocal b
がunset
であっても、そこにとどまります
g() { local b; unset b; eval $1=bar; } # WRONG
g b # Still conflicts with `local b'
echo $b # b is empty unexpected
私はこれを行う方法を発見したが、私はこれがどのように正しいことを確認していない。
Newfun()
{
local var1="$1"
eval $var1=2
# or can do eval $1=2 if no local var
}
var=1
echo var is $var # $var = 1
newfun 'var' # pass the name of the variable…
echo now var is $var # $var = 2
だから、私たちが使用するその値とは対照的に、変数名を渡し、evalを...
バッシュは、それに組み込まれた参照のようなものを持っていないので、基本的にあなたがやりたいことができるだろう唯一の方法は、機能にあなたがそれを変更したいグローバル変数の名前を渡すことです。その場合でも、あなたはeval
書が必要になります。
boo() {
eval ${1}="new"
}
SOME_VAR="old"
echo $SOME_VAR # old
boo "SOME_VAR"
echo $SOME_VAR # new
私はbashが自動的に名前の間接参照に格納された変数の値にアクセスするので、あなたがここに間接参照を使用することができるとは思いません。それはあなたにそれを設定する機会を与えるものではありません。
[OK]を、ので、この質問は、今いくつかの時間のために「本当の」解決のために待っている、と私たちは今、すべてではeval使用せずにこれを実現することができると言うことをうれしく思います。
覚えておくべきののキーは、少なくとも私の例では、呼び出し先として呼び出し側の両方の参照を宣言することです。
#!/bin/bash
# NOTE this does require a bash version >= 4.3
set -o errexit -o nounset -o posix -o pipefail
passedByRef() {
local -n theRef
if [ 0 -lt $# ]; then
theRef=$1
echo -e "${FUNCNAME}:\n\tthe value of my reference is:\n\t\t${theRef}"
# now that we have a reference, we can assign things to it
theRef="some other value"
echo -e "${FUNCNAME}:\n\tvalue of my reference set to:\n\t\t${theRef}"
else
echo "Error: missing argument"
exit 1
fi
}
referenceTester() {
local theVariable="I am a variable"
# note the absence of quoting and escaping etc.
local -n theReference=theVariable
echo -e "${FUNCNAME}:\n\tthe value of my reference is:\n\t\t${theReference}"
passedByRef theReference
echo -e "${FUNCNAME}:\n\tthe value of my reference is now:\n\t\t${theReference},\n\tand the pointed to variable:\n\t\t${theVariable}"
}
# run it
referenceTester
評価は、その危険なので、ユーザーが設定できる文字列に使用すべきではありません。何かのように「という文字列; RM -rf〜」悪いなります。だから、一般的にその最高のあなたはそれを心配する必要はありません解決策を見つけることがます。
コメントが述べたように、しかし、evalのは、渡された変数を設定することが必要になります。
$ y=four
$ four=4
$ echo ${!y}
4
$ foo() { x=$1; echo ${!x}; }
$ foo four
4
#!/bin/bash
append_string()
{
if [ -z "${!1}" ]; then
eval "${1}='$2'"
else
eval "${1}='${!1}''${!3}''$2'"
fi
}
PETS=''
SEP='|'
append_string "PETS" "cat" "SEP"
echo "$PETS"
append_string "PETS" "dog" "SEP"
echo "$PETS"
append_string "PETS" "hamster" "SEP"
echo "$PETS"
出力:
cat
cat|dog
cat|dog|hamster
その機能を呼び出すための構造は次のとおりです。
append_string name_of_var_to_update string_to_add name_of_var_containing_sep_char
変数の名前は、追加する文字列を値として通常の方法を渡されながらペットと9月についてのfuctionに渡されます。 "$ {!1}" グローバルPETS変数の内容を参照します。変数が空とCONTENSであることを初めに、我々は関数を呼び出すたびに追加されます。必要に応じて区切り文字を選択することができます。 「エバール」始まる行はペット変数を更新します。
これはUbuntuのbashシェル上で私のためにどのような作品です。
#!/bin/sh
iteration=10
increment_count()
{
local i
i=$(($1+1))
eval ${1}=\$i
}
increment_count iteration
echo $iteration #prints 11
increment_count iteration
echo $iteration #prints 12