Reputation: 143
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
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:
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
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
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
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 field1
: Print each lineUpvotes: 2