Skip to main content
7 of 11
removed invocations of the split+glob operator which doesn't make sense here. Moved GNU's -i option before arguments so it still works with POSIXLY_CORRECT on.
Stéphane Chazelas
  • 585.1k
  • 96
  • 1.1k
  • 1.7k

Yes, in both bash and zsh you can serialize the contents of a variable in a way that is easy to retrieve using the declare builtin and the -p argument. The output format is such that you can simply source the output to get your stuff back.

 # You have $VAR already with your stuff
 declare -p VAR > serialized_VAR.sh

Either later in your script or in another script altogether, you can get your stuff back like this:

# Load up the serialized data back into $VAR 
source serialized_VAR.sh

How portable this is beyond bash and zsh I don't know. It works in sh for me in testing but I don't know what the POSIX standard is on this.


You could generalize this a little bit and make pair of functions to save stuff to a folder of serialized data and read it back on demand. Obviously you would need to be aware that the stuff in the serialized directory will get executed as shell code so securing it is paramount to your script's security!

# Did you see the warning? Don't do this if you can't trust the files
# in ./serialized as they will be executed as part of your script!
mkdir -p ./serialized

serialize() {
    declare -p "$1" |
      sed 's/^typeset/& -g/;s/^declare/& -g/' > "./serialized/$1.sh"
}

deserialize() {
    source "./serialized/$1.sh"
}

Note: the dirty hack with sed to add the -g flag to the declare statement. Without this declare would create a local variable when run again from inside the other function. Also typeset is for zsh, declare for bash so you could clean that up if you were only running one or the other. There is probably a cleaner way to do this, feel free to suggest one!

Usage would look like this:

FOO=(an array or something)
BAR=$(uptime)

serialize FOO
serialize BAR

unset FOO BAR
# <snip> later....

deserialize FOO
deserialize BAR

echo "FOO: $FOO\nBAR: $BAR"

If keeping the values in a single file is a must, you could do something like so:

touch ./serializedvars.sh

serialize() {
    sed -i "/^$1/d;/^typeset[^=]*$1/d;/^declare[^=]*$1/d" ./serializedvars.sh
    declare -p "$1" |
      sed 's/^typeset/& -g/;s/declare/& -g/' >> ./serializedvars.sh
}

deserialize() {
     source <(sed -n "/^$1=/p;/^typeset[^=]*$1/p;/^declare[^=]*$1/p" ./serializedvars.sh)
}

Note: again some of the complexity of the expressions here are to accommodate both bash and zsh output formats from declare -p. One or the other would be notably simpler.

Caleb
  • 72k
  • 19
  • 203
  • 233