1

How can I replace the value of a column and store the output into the same file?

example input, file:

 #car|year|model
 toyota|1998|corrola
 toyota|2006|yaris
 opel|2001|corsa

replace "corrola" with "corrolacoupe" and store it to the input file

#car|year|model
toyota|1998|corrolacoupe
toyota|2006|yaris
opel|2001|corsa

I have tried this

awk -F '|' -v col=$column -v val=$value '/^[^#]/ FNR==NR  {print $col = val }' OFS='|'  $FILE >> $FILE
Eric Renouf
  • 13,950
  • 3
  • 45
  • 67
  • What version of `awk` are you using/do you need to support. Do you need a portable solution, or is `gawk` OK? If you have `gawk` you could consider it's `gawk -i inplace` or if you have a `sed` that supports it use the `-i` flag (sometimes requiring an argument), or you could use something like `ed` to truly modify the file in place – Eric Renouf Oct 15 '17 at 12:30
  • no i cant do it with gawk –  Oct 15 '17 at 12:36
  • also have a look at this answer: ["bash redirect input from file back into same file"](https://stackoverflow.com/a/6696881/5092659) – Samuel Kirschner Oct 15 '17 at 12:52
  • i want to store the output durectly to the input file –  Oct 15 '17 at 12:58
  • @Antrebp, can you clarify your question a bit? What are the conditions for replacement? Line/column/value? – randomir Oct 15 '17 at 13:02
  • I suggest to copy the file into a temporary file, edit it with awk and then copy it back again. – Cyrus Oct 15 '17 at 13:03
  • Regarding the "replace in the same file" part - that's possible only then deleting characters, not adding, as you are in your example. The only possibility is to create a new, temporary file, and then replace the original with that file. – randomir Oct 15 '17 at 13:06
  • i take from terminal an input that told me to change the string of 2nd line and 3rd column –  Oct 15 '17 at 13:07
  • Are you counting commented lines, when you say 2nd line? – randomir Oct 15 '17 at 13:08
  • I fixed the answer on the semaphore question. It was me who mistakenly had the _exit in the parent. I moved it to the child. Now if you remove all the sem_posts and sem_waits, the children will run in parallel. (You'll get the output lines in random order depending on how the OS decides to run the processes.) – Petr Skocik Nov 22 '17 at 19:53

3 Answers3

0

To simply replace the value in (row,col) with a new value:

$ awk -F'|' -v OFS='|' -v row=2 -v col=3 -v val=corollacoupe 'NR==row {$col=val} 1' file 
#car|year|model
toyota|1998|corollacoupe
toyota|2006|yaris
opel|2001|corsa

This will set the value of input field col to val, but only in the input record row. The 1 in the end will ensure each record is printed by default. Input and output field separators are set via -F option and OFS variable.

If you need to make these changes in-place, create a temporary output file and then copy it over the original:

$ awk ... file >file.tmp && cp file{.tmp,}

Alternatively, in GNU awk, you can use the inplace library via -i inplace option:

$ awk -i inplace -F'|' -v OFS='|' -v row=2 -v col=3 -v val=corollacoupe 'NR==row {$col=val} 1' file 

If you wish to skip the comments, and count only non-comment rows:

$ awk -F'|' -v OFS='|' -v row=1 -v col=3 -v val=x '/^[^#]/ {nr++} nr==row {$col=val} 1' file 
#car|year|model
toyota|1998|x
toyota|2006|yaris
opel|2001|corsa
randomir
  • 17,989
  • 1
  • 40
  • 55
  • this is very helpfull bua i want to store the output durectly to the input file –  Oct 15 '17 at 14:18
  • Unfortunately, you can't. By writing at the beginning you would overwrite the contents of the original file. You must create a temporary file (see second section in my answer). In GNU `awk` you can use the `inplace` library (see my update). – randomir Oct 15 '17 at 14:25
0

An ed solution that modifies the file in-place without any temporary files could be something like:

ed "$FILE" <<< $',s/|corrola$/|corrolacoupe/g\nw'

which uses an ANSI-C string to prevent special characters from being treated specially, then matches |corrola at the end of any line and replaces it with |corrolacoupe. Then we issue the w command to ed to have it write the file back out

Eric Renouf
  • 13,950
  • 3
  • 45
  • 67
0

A really simple solution.

darby@Debian:~/Scrivania$ cat file
#car|year|model
toyota|1998|corrola
toyota|2006|yaris
opel|2001|corsa
darby@Debian:~/Scrivania$ sed -ri 's@^(.+)\|(.+)\|corrola$@\1|\2|corrolacoupe@' file
darby@Debian:~/Scrivania$ cat file
#car|year|model
toyota|1998|corrolacoupe
toyota|2006|yaris
opel|2001|corsa
darby@Debian:~/Scrivania$
Darby_Crash
  • 446
  • 3
  • 6