简体   繁体   中英

How to add a constant number to all entries of a row in a text file in bash

I want to add or subtract a constant number form all entries of a row in a text file in Bash.

eg. my text file looks like:

21.018000 26.107000 51.489000 71.649000 123.523000 127.618000 132.642000 169.247000 173.276000 208.721000 260.032000 264.127000 320.610000 324.639000 339.709000 354.779000 385.084000

(it has only one row) and I want to subtract value 18 from all columns and save it in a new file. What is the easiest way to do this in bash?

Thanks a lot!

Use simple awk like this:

awk '{for (i=1; i<=NF; i++) $i -= 18} 1' file >> $$.tmp && mv $$.tmp file    

cat file
3.018 8.107 33.489 53.649 105.523 109.618 114.642 151.247 155.276 190.721 242.032 246.127 302.61 306.639 321.709 336.779 367.084

Taking advantage of awks RS and ORS variables we can do it like this:

awk  'BEGIN {ORS=RS=" "}{print $1 - 18 }' your_file > your_new_filename

It sets the record separator for input and output to space. This makes every field a record of its own and we have only to deal with $1 .

Give a try to this compact and funny version:

$ printf "%s 18-n[ ]P" $(cat text.file) | dc

dc is a reverse-polish desk calculator (hehehe).

printf generates one string per number. The first string is 21.018000 18-n[ ]P . Other strings follow, one per number.

21.018000 18 : the values separated with spaces are pushed to the dc stack.

- Pops two values off, subtracts the first one popped from the second one popped, and pushes the result.

n Prints the value on the top of the stack, popping it off, and does not print a newline after.

[ ] add string (space) on top of the stack.

P Pops off the value on top of the stack. If it it a string, it is simply printed without a trailing newline.

The test with an additional sed to replace the useless last (space) char with a new line:

$ printf "%s 18-n[ ]P" $(cat text.file) | dc | sed "s/ $/\n/" > new.file
$ cat new.file
3.018000 8.107000 33.489000 53.649000 105.523000 109.618000 114.642000 151.247000 155.276000 190.721000 242.032000 246.127000 302.610000 306.639000 321.709000 336.779000 367.084000

----

For history a version with sed :

$ sed "s/\([1-9][0-9]*[.][0-9][0-9]*\)\{1,\}/\1 18-n[ ]P/g" text.file | dc

With Perl which will work on multiply rows:

perl -i -nlae '@F = map {$_ - 18} @F; print "@F"' num_file
#     ^ ^^^^                               ^
#     | ||||                               Printing an array in quotes will join
#     | ||||                               with spaces
#     | |||Evaluate code instead of expecting filename.pl
#     | ||Split input on spaces and store in @F
#     | |Remove (chomp) newline and add newline after print
#     | Read each line of specified file (num_file)
#     Inplace edit, change original file, take backup with -i.bak

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM