Variable in Bash Script That Keeps It Value from the Last Time Running

Variable in Bash Script that keeps it value from the last time running

You can't, but you can use a file to do it

#!/bin/bash

valuefile="/tmp/value.dat"

# if we don't have a file, start at zero
if [ ! -f "$valuefile" ]; then
value=0

# otherwise read the value from the file
else
value=$(cat "$valuefile")
fi

# increment the value
value=$((value + 1))

# show it to the user
echo "value: ${value}"

# and save it for next time
echo "${value}" > "$valuefile"

bash—Better way to store variable between runs?

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.

How to use Unix variables to set and retain values across session {bash}

Shell variables are stored per-process, since each shell script is its own process, you cannot persist variables across processes this way. There are various ways to communicate between processes, though:

  1. Pipes
  2. Shared Memory
  3. Message Queue
  4. Semaphores
  5. Files

For your purposes, it would seem that files are the easiest approach. Using bash, to write to the file:

echo $VAR > /tmp/process.tmp.file.txt

and read from it:

export VAR=`cat /tmp/process.tmp.file.txt`

remember bash variable for running script again

Launching the script from terminal makes the script inherit the environment variables from your terminal. Any environment variables set within that script are only valid during the execution time of the same script. As soon as it exits, away goes the environment variables.

You would have to use something else, files for instance, to keep track of changes during multiple executions of the script.

Bash: increment a variable from a script every time when I run that script


#!/bin/bash    
n=0;#the variable that I want to be incremented
next_n=$[$n+1]
sed -i "/#the variable that I want to be incremented$/s/=.*#/=$next_n;#/" ${0}
echo $n

Variables getting reset after the while read loop that reads from a pipeline

I ran into this problem yesterday.

The trouble is that you're doing find $loc -name "*.bsp" | while read. Because this involves a pipe, the while read loop can't actually be running in the same bash process as the rest of your script; bash has to spawn off a subprocess so that it can connect the the stdout of find to the stdin of the while loop.

This is all very clever, but it means that any variables set in the loop can't be seen after the loop, which totally defeated the whole purpose of the while loop I was writing.

You can either try to feed input to the loop without using a pipe, or get output from the loop without using variables. I ended up with a horrifying abomination involving both writing to a temporary file AND wrapping the whole loop in $(...), like so:

var="$(producer | while read line; do
...
echo "${something}"
done)"

Which got me var set to all the things that had been echoed from the loop. I probably messed up the syntax of that example; I don't have the code I wrote handy at the moment.

How do I set a variable to the output of a command in Bash?

In addition to backticks `command`, command substitution can be done with $(command) or "$(command)", which I find easier to read, and allows for nesting.

OUTPUT=$(ls -1)
echo "${OUTPUT}"

MULTILINE=$(ls \
-1)
echo "${MULTILINE}"

Quoting (") does matter to preserve multi-line variable values; it is optional on the right-hand side of an assignment, as word splitting is not performed, so OUTPUT=$(ls -1) would work fine.

Bash - Using a static variable (aka Command line Russian Roulette)

Short answer: No, bash doesn't have "static" variables.

Longer: When your "C" program finishes its run, the "static" variable is lost. The same is applied for the bash script. So, you must decide what you want:

  • run the script once, simulate the revolver (and you can use global variable to hold the revolver status)
  • want preserve the revolver's cylinder status between each script run, so you need use some external storage to preserve the data. (for example file).

From you question i guessed the second version, so you must use file to hold the revolver status. For the game, you should divide the problem to different parts:

  • roll - (roll the revolver's cylinder (random bullet position))
  • shoot - (move the cylinder by one position and check the bullet)

I would do this as the following:

  1. define the revolver for example as /tmp/revolver.

    • It will have 6 lines, in each line could be 2 values: 0 - no bullet, 1 - bullet
    • the hammer is in the 1st line - so, if the bullet is in the first line (e.g. the 1st line has value 1) the bullet will fire.
    • each "roll" ensures than exactly ONE bullet is in the cylinder
    • when shooting - once the bullet is fired, will not fire again, so any number of subsequent shots will not fire again
  2. the roll "command". Defined as an bash function and saved as ./roll command.

revolver="/tmp/revolver"
roll() {
cyl=(0 0 0 0 0 0) # empty cylinder
cyl[$(($RANDOM % 6))]=1 # one bullet at random position
printf "%d\n" "${cyl[@]}" >"$revolver" # save
}
roll #do the roll

now, you can do bash roll (or after the chmod 755 roll) simply ./roll and your revolver is loaded with one bullet. Run the ./roll few times and after each ./roll check the bullet position with cat /tmp/revolver.


  1. the shoot command should:

    • rotate the lines by one position (as in the real revolver)
    • and cock the hammer - e.g. check the value of the 1st line
revolver="/tmp/revolver"

rollone() {
at_hammer=$1 # store what is under the hammer
shift # shift the rest by one position
printf "%d\n" "$@" 0 > "$revolver" # save new cylinder the status

# note, we adding to the last position 0,
# because when the bullet is fired it will not fire again
# out digital revolver is not jamming

echo $at_hammer # return the bullet yes/no
}

shoot() {
cyl=($(<"$revolver")) #load the revolver status
return $(rollone "${cyl[@]}") #make the shoot, roll the cylinder and return the status
}

boom() { echo "Boom"; } #the "boom" action
click() { echo "Click"; } #the "click" action

shoot && click || boom #the actual shot

Now you can play the game:

  • a. ./roll - load the revolver with one bullet and roll the cylinder
  • b. ./shoot - any number of times

The whole game as script.

Variant A - roll once and shooting multiple times i

./roll
while :
do
./shoot
done

this will output something like:

Click
Click
Boom
Click
Click
... and forever ...
Click

Variant B - roll (e.g. reload with 1 bullet) between each shot

while :
do
./roll
./shoot
done

this will prints e.g.:

Click
Click
Boom
Boom
Click
Click
Click
Boom
Click
Click
Click
Click
Click
Click
Click
Click
Click
Boom
Click
... etc ...

Also, you could extend/modify the scripts with one more command: load and redefine your revolver as:

  • load - will load one (or more) bullet(s) into the cylinder
  • roll - will rotate the cylinder by the random number of positions (but NOT reloads the bullet) - e.g. after the fired bullet the roll will rotate only empty cylinder
  • shoot - fire the gun (no modification needed).


Related Topics



Leave a reply



Submit