0

我想编写一个函数,它接受一个数组变量名并更新内容。例如:

ARRAY1=("test 1" "test 2" "test 3")
toUpper ARRAY1

for arg in "${ARRAY1[@]}"; do
  echo "arg=$arg"
done

# output
arg=TEST 1
arg=TEST 2
arg=TEST 3

我做了一个粗略的尝试,这需要输入数组的副本。使用间接引用,我能够创建输入变量的副本。数组的副本用于获取元素的计数。如果有更好的方法来做到这一点,请告诉我。

function toUpper() {
  local ARRAY_NAME=$1
  local ARRAY_REF="$ARRAY_NAME[@]"
  # use an indirect reference to copy the array so we can get the count
  declare -a ARRAY=("${!ARRAY_REF}")

  local COUNT=${#ARRAY[@]}

  for ((i=0; i<$COUNT; i++)); do
    local VAL="${ARRAY[$i]}"
    VAL=$(echo $VAL | tr [:lower:] [:upper:])
    echo "ARRAY[$i]=\"$VAL\""
    eval "$ARRAY_NAME[$i]=\"$VAL\""
  done
}

ARRAY1=( "test" "test 1" "test 3" )

toUpper ARRAY1

echo
echo "Printing array contents"
for arg in "${ARRAY1[@]}"; do
  echo "arg=$arg"
done
4

2 回答 2

5

使用BASH 4.3+你可以做到

arr=( "test" "test 1" "test 3" )
toUpper() { declare -n tmp="$1"; printf "%s\n" "${tmp[@]^^}"; }

toUpper arr
TEST
TEST 1
TEST 3

更新:反映原始数组的变化:

toUpper() {
   declare -n tmp="$1"; 
   for ((i=0; i<"${#tmp[@]}"; i++)); do
      tmp[i]="${tmp[i]^^}"
    done;
}

arr=( "test" "test 1" "test 3" )
toUpper arr
printf "%s\n" "${arr[@]}"
TEST
TEST 1
TEST 3

更新 2:这是一种使其在旧 BASH(4 之前)版本中工作的方法,无需eval

upper() {
   len=$2
   for ((i=0; i<len; i++)); do
      elem="${1}[$i]"
      val=$(tr '[:lower:]' '[:upper:]' <<< "${!elem}")
      IFS= read -d '' -r "${1}[$i]" < <(printf '%s\0' "$val")
   done;
}

arr=( "test" "test 1" "test 3" )
upper arr ${#arr[@]}
printf "%s\n" "${arr[@]}"
TEST
TEST 1
TEST 3
于 2015-04-06T14:43:06.263 回答
1

anubhava 的答案非常适合 bash 4.3 或更高版本。为了支持 bash 3,可以使用eval(非常谨慎,使用 生成的字符串printf %q)来替换 namevars 的使用,并tr替换${foo^^}大写的扩展:

toUpper() {
  declare -a indexes
  local cmd idx item result
  printf -v cmd 'indexes=( "${!%q[@]}" )' "$1"; eval "$cmd"
  for idx in "${indexes[@]}"; do
     printf -v cmd 'item=${%q[%q]}' "$1" "$idx"; eval "$cmd"
     result=$(tr '[:lower:]' '[:upper:]' <<<"$item")
     printf -v cmd '%q[%q]=%q' "$1" "$idx" "$result"; eval "$cmd"
  done
}
于 2015-04-06T17:17:56.370 回答