Bash: how to save and restore associative arrays with keys that contain square brackets or other special characters

Problem

Getting the result declare -pfor a valid Bash associative array in which the keys contain square brackets results in a bad array error .

Testing procedure

do:

$ declare -A array
$ key='var[0]'
$ array["$key"]=37
$ echo ${array["$key"]}
37
$ declare -p array > def.sh
$ cat def.sh
declare -A array='(["var[0]"]="37" )'
$ . def.sh
bash: [var[0]]=37: bad array subscript

In the code above, note:

  • I can specify a key containing square brackets: var[0]
  • Key quoted for setters and getters
  • I can complete the assignment using this key
  • I can get the value from an associative array using this key
  • Usage declare -pI can save this definition in a file:def.sh
  • An def.sherror is thrown while searching for a file .

My environment

  • Bash 4.2.46 (1) -release (x86_64-redhat-linux-gnu).
  • CentOS 7.3.1611 (Core)

declare -p array > def.sh :

{
echo 'declare -A array'
for Key in "${!array[@]}"; do
   EscapedKey="$(sed 's|"|\\"|g' <<<"$Key")"
   echo "array[\"$EscapedKey\"]=${array["$Key"]}"
done
} > def.sh

def.sh. , , . , , , . - , , .

- shopt, set -o <option> - , , , ? , .

+4
1

bash 4.2. 4.3.

, bash 4.2, 4.2.53 4.3 http://ftp.gnu.org/gnu/bash/ . 4.3 4.4 - . bash 4.3 declare

declare -A array='(["var[0]"]="37" )'

, 4.2. 4.4 , :

declare -A array=(["var[0]"]="37" )

.

complete_fullquote , ​​ 4.4, .

, >= 4.3 , , , .

, sed, ( bash 4.2):

function array2file {
  # local variable for the keys
  declare -a keys

  # check if the array exists, to protect against injection
  # by passing a crafted string
  declare -p "$1" >/dev/null || return 1;

  printf "declare -A %s\n" "$1"

  # create a string with all the keys so we can iterate
  # because we can't use eval at for declaration
  # we do it this way to allow for spaces in the keys, since that valid
  eval "keys=(\"\${!$1[@]}\")"

  for k in "${keys[@]}"
  do
    printf "%s[\"${k//\"/\\\\\"}\"]=" "$1"
    # the extra quoting here protects against spaces
    # within the element value - injection doesn't work here
    # but we still need to make sure there consistency
    eval "printf \"\\\"%s\\\"\n\" \"\${$1[\"${k//\"/\\\"}\"]}\""
  done
}

, . , . :

array2file array > ./def.sh

array - , . , , , , .

, printf for, $1 ${2:-$1} printf , , . , 2 (, ). , .

, .

+5

Source: https://habr.com/ru/post/1683631/


All Articles