0

I have a file like a database where I save name,surname,date of birth, gift, and I want to know if this person have got a gift from us or not. Those dates are splited by tabs in the file, one person per line, like:

name1  surname1  dateofbirth1  gift1
name2  surname2  dateofbirth2  gift2

Inside gift colum, I save "Yes" or "No" and my code looks like:

while IFS=$'\t' read -r name surname dob gift; do
    if [[ "$gift" == "No" ]]; then
        echo "Congrats, here is your gift
        gift=Yes
    fi
done < "file.txt"

But the gift colum, don't seems to change to yes, only seems to be there as an aux var. How can I change the value of that line, in that colum, to yes?

Rui F Ribeiro
  • 55,929
  • 26
  • 146
  • 227
Multi
  • 83
  • 1
  • 1
  • 3
  • 1. Is `gift` actually set as `yes` in your file? 2. Did you create the `file.txt` on Windows but are running the code on a Linux platform? – roaima Apr 07 '19 at 16:11
  • By default, gift is set as No. So inside the loop, I want to check those ones who have No and change it to yes. And no, file it's made on Linux (Ubuntu). – Multi Apr 07 '19 at 16:15
  • 2
    @Multi17 The simple act of `read`-ing a line does not bind that line to the variables you specified for receiving the line’s fields. You need to rewrite that line with the updated value of `"${gift}"`. As to how do that, replacing it ”in-place” (i.e. on the same file and line as your source `file.txt`) cannot be done simply. What you may do in a simple way is just output the updated line, along with all the other lines, and redirect that output to another file, which you’ll *then* move to `file.txt` to replace the original file. – LL3 Apr 07 '19 at 16:20
  • @LL3 Okey, thanks for explain this. I will give it a go to it! – Multi Apr 07 '19 at 16:21

1 Answers1

0

Reading a value from a file and then changing the variable that holds that value will not change the value in the file.

Instead, you would have to detect what values need changing, change them, and then output the complete file (including modified values) to a new file. This new file can then be moved to the original name, replacing the old file.

Also, parsing text in the shell is generally to be avoided. Instead, consider using something like awk for that:

awk -F '\t' 'BEGIN { OFS=FS }
             $4 == "No" { print "Congrats, here is your gift" >"/dev/stderr" }
             { $4 = "Yes"; print }' file.txt >newfile.txt

This would read through the file line by line and whenever the fourth column says No, it outputs the text Congrats, here is your gift.

Then, for every line, the fourth column is unconditionally set to Yes before the whole line is printed.

The way the program is written and run above, the Congrats... message will appear in the terminal (it's written to the standard error stream) while the updated contents of the file will be written to the new file called newfile.txt.

The BEGIN block at the start of the code simply sets the output field separator, OFS, to the same value as the input field separator, FS, which is set to a tab character on the command line using -F '\t'.

Kusalananda
  • 320,670
  • 36
  • 633
  • 936