Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Saving data in bash?

Tags:

bash

shell

Ok so I was wondering if it is possible to save like a variable in bash. I am writing a script where you build like farms and mines and I was just wondering if it is possible to bring back those variables even after I stopped the program and then got back on. So lets say I have built 4 farms farms would be farm=4, can I bring this variable back somehow? I know how to make a page that you can make a high scores list on (Which I did for a guessing game.), but this I don't know if it is possible in bash.

like image 704
Lifetake Avatar asked Dec 21 '22 12:12

Lifetake


2 Answers

You can write everything in a file in that format:

farm=4
myname=gniourf

And then source that file:

#!/bin/bash

# Recover the saved states:
source file_where_i_saved_my_stuff

# Now you can recover all your variables!
echo "$farm"
echo "$myname"

Edit

Since you want to know how you can save your variables, here's a quick hint, with a lot of stuff that hasn't been given in the other answer.

Alright, so you want to save some variables in a file, and be able to later source this file to recover the value of these variables. Of course, you'll have a lot of variables, and you don't want to explicitly write down the list of all the variables you'll have to save, which is error prone and retarded. I mean, nobody wants to do the following:

cat <<EOF > file_where_i_saved_my_stuff
variable1=$variable1
variable2=$variable2
...
variable1000000=$variable1000000
EOF

In fact, you don't want to do this at all for many reasons. Now, I'll address the solution:

The method relies on this stupid thing (together with good bash practice and knowledge): name all the variables you want to save using a prefix, e.g., variable_i_want_to_save_, so that you'll have variables like variable_i_want_to_save_number_of_farms and variable_i_want_to_save_color_of_granny_dress and so on. Do not use this prefix with variables you don't want to save.

Smart thing #1

bash has a wonderful thing: you can get the name of all variables that start with a certain prefix like so:

"${!prefix@}"

This will expand to a list of all known variables that start with prefix prefix.

Hence, in our case,

for i in "${!variable_i_want_to_save_@}"; do

will loop through the name of all variables that are prefixed by our wonderful prefix. Isn't that great?

Smart thing #2

If I am in the following situation:

a=1
b=2
variablename="a"

how do I get the value of the variable the name of which is the value of the variable variablename? Easy, use the "${!variablename}" construct. Look:

$ a=1
$ b=2
$ variablename=a
$ echo "${!variablename}"
1

The ${!prefix@} and ${!variablename} expansions are explained in the Shell Parameter Expansion section of the Bash reference (you'll have to scroll down a bit to get there).

(Broken) Solution

Then you're good for a broken solution to save your variables in a file, like so:

save_data_to_file() {
    for i in "${variable_i_want_to_save_@}"; do
        echo "$i=${!i}"
    done > file_where_i_saved_my_stuff
}

This is really efficient and cool, but really broken if you have spaces or junk characters of any sort in your variables (which can (and should) appear). Oh dear.

Solution

The good thing for you is that bash has this wonderful printf command with its amazing format specification %q that will

quote the argument in a way that can be reused as shell input

(I got this from help printf). It's amazing, it's absolutely fantastic, just try it:

$ a=$'bonjour les amis !\ncomment ça va ?'
$ # You see, variable a has a lot of stupid characters:
$ echo "$a"
bonjour les amis !
comment ça va ?
$ # and printf does a wonderful job:
$ printf '%s=%q\n' a "$a"
a=$'bonjour les amis!\ncomment \303\247a va ?'

You couldn't dream of something as good as this. Or maybe you could, but please just admit it's awesome!

So, here you are with your wonderful way to save your variables in a file:

save_data_to_file() {
    for i in "${!variable_i_want_to_save_@}"; do
        printf '%s=%q\n' "$i" "${!i}"
    done > file_where_i_saved_my_stuff
}

Note that sourcing an external file like this leads to obvious security issues, so make sure you only use this method with care!

like image 98
gniourf_gniourf Avatar answered Dec 23 '22 01:12

gniourf_gniourf


You can save all needed variables in a file (using here-doc):

cat<<EOF>/path/to/file
var1="$var1"
var2="$var2"
EOF

and to recreate your previous environment :

source /path/to/file

or

. /path/to/file

EXPLANATIONS

  • the place where to put the here-doc depends of your code, can be the last lines if you don't have to save variables in loops by example
  • the place to put the source command is the top of your script after the shebang

Help said :

$ LANG=C help source

source: source filename [arguments] Execute commands from a file in the current shell.

Read and execute commands from FILENAME in the current shell.  The
entries in $PATH are used to find the directory containing FILENAME.
If any ARGUMENTS are supplied, they become the positional parameters
when FILENAME is executed.

Exit Status:
Returns the status of the last command executed in FILENAME; fails if
FILENAME cannot be read.

NOTE

if you want for some reasons to dynamically generate the files with pattern matching on variable names :

  • by suffix : printf '%q\n' $(set | grep "suffix=") > save_file
  • by prefix : printf '%q\n' $(set | grep "^prefix") > save_file

Thanks gniourf_gniourf for printf trick.

like image 31
Gilles Quenot Avatar answered Dec 23 '22 00:12

Gilles Quenot