0

Fairly new to linux and I'm working on bash script at the moment. The task at hand is that with help of a script together with a argument that it should increase/decrease a value in a file with either +1 or -1.

I'm presuming this can be done to a txt file.

Example

  • increase the value by 1 in the file
    ./script.sh in
    
  • decrease the value by 1 in the file
    ./script.sh out
    

If someone can point at the right way, give example or solutions would be greatly appreciated.

AdminBee
  • 22,803
Zetzki
  • 1
  • 2
    What is the question? Add the script, expected output, and where it's not working, including the actual output, to your question. – Nasir Riley Nov 06 '20 at 09:23
  • 2
    It's unclear what format the file is required to be in (if any in particular). Is the point to write an integer, and only an integer, to a file (because the file is used by some other process), or is the point to be able to use the integer inside the script? – Kusalananda Nov 06 '20 at 09:33

1 Answers1

2

You could do the reading value, incrementing, writing new value with awk, and argument handling in sh:

#! /bin/sh -
file=/path/to/counter
case "$#:$1" in
   (1:in) incr=1;;
  (1:out) incr=-1;;
      (*) echo >&2 'need "in" or "out" as the one and only one argument'
          exit 1
esac

awk -v incr="$incr" ' {print $0 + incr > FILENAME; exit} END {if (!NR) print incr > FILENAME}' 3<> "$file" "$file"

That expects $file contains one line with one number¹ and increments or decrements it. If the line doesn't contain a number or the file is empty, it will be treated as 0. That's better than using shell arithmetic evaluation to do the increment as those are not safe if the input is not guaranteed to have sane values.

If the file didn't exist beforehand, it will be created (via 3<> "$file") and considered as if it contained 0 as well.

Note that that script is not safe against concurrent execution as two instances running at the same time could read the same old value and increase it independantly. To address that, if your system has the flock command, you could replace the awk command with:

{
  flock 3 &&
    awk -v incr="$incr" '
    {print $0 + incr > FILENAME; exit}
    END {if (!NR) print incr > FILENAME}' "$file"
} 3<> "$file"

Where flock obtains an exclusive lock on the file.


¹ the number can be integer or floating point (even potentially expressed in hexadecimal with some awk implementation and in some environment), but note that non-integer numbers are expressed with 6 digits of precision, so 99999.5 would become 100000 and 999999.5 would become 1e+06 after increment. So if dealing with floating point numbers and high values, you may want to add a -v OFMT='%.15g' for instance to increase the precision.