質問

えていただきたいと思いることが可能に引数を渡すにはスクリプト機能により参考:

すなわちいるようになりますの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宣言するために発生した場合、

また、printflocalの両方が動作しません

g() { local b; eval $1=bar; }  # WRONG
g b                            # Conflicts with `local b'
echo $b                        # b is empty unexpected

競合がlocal bunsetであっても、そこにとどまります

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
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top