nacht-falter
nacht-falter

Reputation: 143

Read values from a file, increment or change them and store them again in the same place

So, I have a bash script which reads several variables from different external files, increments or changes these variables and then stores the new values in the files.

Something like this:

var1=$(< file1)
var2=$(< file2)
var3=$(< file3)

# then for example:
((var1=var1+1))
((var1=var1-1))
var3=foo

echo $var1 > file1
echo $var2 > file2
echo $var3 > file3

This works just fine, but I find it a bit bulky, especially when there are a lot of variables stored like this. I think it would be more elegant to store all the values in a single file which could look something like this:

#File containing values
var1=1
var2=2
var3=foo

Unfortunately I can't figure out how to read the values from such a file and store the new values in the same place afterwards? I have looked into sed and awk but so far I couldn't find a solution that works in this particular case.

Any Suggestions?

Upvotes: 2

Views: 1668

Answers (2)

nacht-falter
nacht-falter

Reputation: 143

Ok, since my question appears to have been imprecise I accepted the answer by @anubhava as correct even though it didn't quite work for me. But it seems to be the correct answer to my question and pointed me in the right direction. Based on that answer I found a solution that works for me:

I now have a file named 'storage' containing all the variable names and values like this:

var1 1
var2 1
var3 foo

In my script there are three scenarios:

  1. Incrementing or decrementing silently

A value is read from the file (by searching for the variable name and reading the last field in that line), silently incremented or decremented and saved to the file again:

awk '/var1/{++$NF} {print > "storage" }' storage # incrementing
awk '/var1/{--$NF} {print > "storage" }' storage # decrementing
  1. Toggle between two values

Depending on user input a variable can be set to one of two values for example like this:

PS3="Please choose an option"
options=("Option 1" "Option 2")
select opt in "${options[@]}"
do
    case $opt in
        "Option 1")
            awk '/var2/{$NF=0} {print > "storage" }' storage # this sets the value to 0
            break
            ;;
        "Option 2")
            awk '/var2/{$NF=1} {print > "storage" }' storage # this sets the value to 1
            break
            ;;
    esac
done
  1. Reading user input

The script reads a value from the file and prints it. Then it waits for user input and stores the input in the file

var3=$(awk '/var3/{print $NF}' storage) # reading the current value from the file and storing it in the variable
echo The current value is $var3
read -p "Please enter the new value" var3
awk -v var3="$var3" '/var3/{$NF=var3} {print > "storage" }' storage # writing the new value to the file

This does exactly what I was looking for. So, thank you @anubhava for pointing me in the right direction!

Upvotes: 1

anubhava
anubhava

Reputation: 784958

An awk script can handle this i.e. to find out all name=value lines, find all integer value and increment it:

awk 'BEGIN {FS=OFS="="} NF==2 && $2+0 == $2 {++$2} 1' file

#File containing values
var1=2
var2=3
var3=foo

If you want to save changes inline then use this gnu-awk command:

awk -i inplace 'BEGIN {FS=OFS="="} NF==2 && $2+0 == $2 {++$2} 1' file

Explanation:

  • FS=OFS="=": Set input and output field separator to =
  • NF==2: Number of fields are 2
  • &&: ANDed with
  • $2+0 == $2: Find only numeric values
  • ++$2: increment 2nd field
  • 1: Print each line

Upvotes: 2

Related Questions