views:

36

answers:

1

Hi everyone,
I have a configuration file that has variables and value separate by spaces. I want to take the value (in the second column) of certain matches and inline edit the file, dividing this match by 2. I also would like to preserve spacing and use a ceiling function on the value.

For example, the file: To recap, using an actual example file, if my file was:

OTHER TEXT 1
OTHER TEXT 2
restartfreq        325
dcdfreq            325
xstFreq            325
outputEnergies     325
outputPressure     325
OTHER TEXT 3

Would become:

OTHER TEXT 1
OTHER TEXT 2
restartfreq        163
dcdfreq            163
xstFreq            163
outputEnergies     163
outputPressure     163
OTHER TEXT 3

I would prefer to do this all in a Bash script using Linux commands. I've considered switching to a small c++ program, but for now am sticking with a scripted tool-based solution.

Working towards this, I posted this inquiry last week:
http://stackoverflow.com/questions/3686204/how-can-i-mix-math-with-regexs-in-awk-or-sed/3687341#3687341

I came eventually to a long-winded solution, but ghostdog74 proposed this more eloquent solution:

awk '$1=="restartfreq"{$2=$2/2;}1' file > t && mv t file

This does what I want... almost.

As I said, I also need to implement a ceiling function, and preferably preserve white space -- and I'd like to make it capable of dividing the values of multiple matches, not just one.

Can I do this in a one-liner or small nested awk script? Any tips??


Solution:

I've taken Ghostdog's answer:

awk '$1~/[fF]req|output/{ n=$2/2; sub(/ [0-9][0-9]*$/,n)}1' file

And modified it slightly to allow comments on the end of the line and to perform the ceiling as per my request. I'm going to ask a separate function about how to use short functions in awk one liners.

awk '$1~/restartfreq|dcdfreq|xstFreq|outputEnergies|outputPressure/{ a=$2/2; n= (a== int(a)) ? a : int(a)+1; sub(/ [0-9][0-9]*.*$/,n)}1' file > temp && mv -f temp file

Good work Ghostdog!

+1  A: 
$ awk '$1~/[fF]req|output/{ n=$2/2; sub(/ [0-9][0-9]*$/,n)}1' file
OTHER TEXT 1
OTHER TEXT 2
restartfreq       162.5
dcdfreq           162.5
xstFreq           162.5
outputEnergies    162.5
outputPressure    162.5
OTHER TEXT 3
ghostdog74
Okay that almost does everything I want, but I just noticed that if there's a comment (denoted in this format by ";") the command doesn't work. For example "restartfreq 2500" works, but "restartfreq 2500 ;# 2500steps = every 1.25 ps" doesn't work. Also, any idea on how to do a ceiling function on the number (you could use an if statement, I think?)?
Jason R. Mick
Jason R. Mick
...figured it out, see above (added conditional to perform ceiling op and ".*" to your regex to ignore any comment after the number. Thanks ghostdog!! :)
Jason R. Mick
whoops, the above was rounding, not taking the ceiling. see above my edit to my post for correct conditional.
Jason R. Mick