如何在bash脚本中从内部函数连接到字符串变量?

时间:2017-11-08 22:33:10

标签: string bash append string-concatenation

我希望能够调用一个函数,并保留函数对字符串执行的所有修改。

例如: 我试过这个剧本

#!/bin/bash

change_string() {
  var=$1
  var+=",Hello2"
  echo "Function: $var"
}

myString="Hello1"
change_string $myString

echo "Main: $myString"

这将打印出来:

Function: Hello1,Hello2
Main: Hello1

有没有办法在函数调用中更改$ myString,但是将这些更改保留在main中?我想我可能错过了与传递引用相关的bash中的一些内容?

3 个答案:

答案 0 :(得分:3)

使用Bash 4.3+(namerefs!)

现代版本的bash提供" nameref"支持,允许变量引用另一个变量。

#!/usr/bin/env bash

case $BASH_VERSION in
  [123].*|4.[012].*) echo "This needs bash 4.3 or newer" >&2; exit 1;;
esac

# local variable is prefixed because this will fail if we're passed a variable name we use
# internally; prefixing the local names makes such collisions unlikely.
change_string() {

  # make change_string__var an alias for the variable named in our argument
  declare -n change_string__var=$1

  # append to that variable
  change_string__var+=",Hello2"

  # ...and log the new value, 'cuz that's what the original code did.
  echo "Function: $change_string__var"
}

myString="Hello1"
change_string myString  ## pass variable **name**, not variable value
echo "Main: $myString"

使用Bash 3.x +(间接评估+间接分配)

或者,作为一种不那么新奇的方法,可以使用${!var}进行间接引用,printf -v进行间接分配。

#!/usr/bin/env bash

change_string() {

  # Store the variable name in a regular local variable
  local change_string__var=$1

  # Use ${!var} to get the value of the variable thus named
  local change_string__val=${!change_string__var}

  # Use ''printf -v varname ...'' to assign a new value
  printf -v "$change_string__var" %s "${change_string__val},Hello2"
}

myString="Hello1"
change_string myString
echo "Main: $myString"

答案 1 :(得分:1)

您必须将变量的名称传递给您的函数,而不是其值。一旦你这样做,有几个选择。

最简单的可能是使用nameref(需要bash 4.3或更高版本):

change_string() {
  declare -n var=$1
  var+=",Hello2"
}

$ foo="Hello1"
$ change_string foo
$ echo "$foo"
Hello1,Hello2

在引入namerefs之前,您可以使用declare -g,这需要bash 4.2或更高版本:

change_string () {
  var=$1
  old_val=${!var}
  declare -g "$1=${old_val},Hello2"
}

在4.2之前,你几乎陷入使用eval并且用手指交叉,你没有被代码注入攻击所困扰。

change_string () {
  var=$1
  eval "$1=\$$1,Hello2"
}

但这些方法都不是完全万无一失的;请参阅Bash FAQ 048的this section。我的建议是尽量避免需要这样的功能。

答案 2 :(得分:0)

declare是具有动态范围的罕见语言之一(与通常的词法范围不同)。这意味着函数正在从定义它们的最后一个作用域中访问变量(可能是带有local#!/bin/bash fun() { x="newval" } x=start echo "$x" fun echo "$x" 的赋值或声明。

例如:

start
newval

将打印:

x

这个简单的例子看起来像#!/bin/bash change_string() { myString+=",Hello2" } myString="Hello1" change_string $myString echo "Main: $myString" 是一个简单的全局变量,但它不止于此(范围是动态嵌套的,总是访问最后/前一个范围)。

因此,如果您想更改函数中的变量,只需更改它。

declare -g

您甚至可以通过引用"更改变量"如果您传递变量的名称,则使用varname设置(在外部范围内)通过将文本附加到当前值(通过间接扩展访问),我们知道其名称(change_string() { varname="$1" declare -g "$varname"="${!varname},Hello2" } myString="Hello1" change_string myString # myString is now "Hello1,Hello2" )的变量的值:

Message