Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

bash—Better way to store variable between runs?

Tags:

I've made a bash script which I run every hour with crontab, and I need to store one variable so that I can access it the next time I run it. The script changes the variable every time it runs, so I can't hardcode it in. Right now I am writing it to a txt file and then reading it back. Is there a better way to do it than this? And the way I am reading the txt file is something I found on here, I don't understand it, and it's kinda clunky. Is there not a built in command for this? Anyway, here's the applicable code, with some of the variables changed to make it easier to read.

while read x; do   var=$x done < var.txt  # Do some stuff, change var to a new value  echo $var > var.txt 

The variable is only a single integer, so the text file feels overkill.

like image 266
shardbearer Avatar asked Sep 08 '12 21:09

shardbearer


People also ask

Should you quote variables in bash?

General rule: quote it if it can either be empty or contain spaces (or any whitespace really) or special characters (wildcards). Not quoting strings with spaces often leads to the shell breaking apart a single argument into many.

What is Dash S in bash?

From man bash : -s If the -s option is present, or if no arguments remain after option processing, then commands are read from the standard input. This option allows the positional parameters to be set when invoking an interactive shell.

How do you store shell variables?

To store the output of a command in a variable, you can use the shell command substitution feature in the forms below: variable_name=$(command) variable_name=$(command [option ...] arg1 arg2 ...) OR variable_name='command' variable_name='command [option ...]


2 Answers

There's no need to use var; x will be in scope for the current shell. Alternately,

read var < var.txt # do stuff with var echo $var > var.txt 

I recommend using a simple text file to store the variable. However, there is the (highly questionable) option of a self-modifying script. FOR ENTERTAINMENT PURPOSES ONLY!

#!/bin/bash  read val < <( tail -n 1 "$0" )  (( val++ )) echo "$val"  tmp=$(mktemp /tmp/XXXXXXX) sed '$s/.*/'$val'/' "$0" > "$tmp" mv "$tmp" "$0"  exit 0 

The key is to have the next-to-last line be the exit command, so nothing after it will execute. The last line is the variable value you want to persist. When the script runs, it reads from its own last line. Before it exits, it uses sed to write a copy of itself toa temp file, with the last line modified with the current value of the persistent value. Then we overwrite the current script with the temp file (assuming we will have permission to do so).

But seriously? Don't do this.

like image 125
chepner Avatar answered Oct 03 '22 20:10

chepner


I know this is an old question. But, I still decide to post my solution here in the hope that it might be helpful to others who come here in search of a way to serialize env vars between sessions.

The simple way is just write "var_name=var_value" into a file, say "./environ". And then "source ./envrion" in following sessions. For example:

echo "var1=$var1" > ./environ 

A more comprehensive (and elegant?) way which persist all attributes of variables is to make use of "declare -p":

declare -p var1 var2 > ./environ # NOTE: no '$' before var1, var2 

Later on, after "source ./envrion" you can get var1 var2 with all attributes restored in addition to its value. This means it can handle arrays, integers etc.

One caveat for the "declare -p xx", though: if you wrap the "source ./environ" into a function, then all sourced variables are visible within the function only because "declare" by default declares variables as local ones. To circumvent this, you may either "source" out of any function (or in your "main" function) or modify the ./environ to add "-g" after declare (which makes corresponding variable global). For instance:

sed -i 's/^declare\( -g\)*/declare -g/' ./environ # "\( -g\)?" ensure no duplication of "-g" 
like image 33
Lungang Fang Avatar answered Oct 03 '22 22:10

Lungang Fang