[SOLVED] Bash Newbie: Looking for a script that can find numbers in txt-file and add=sum one number
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
Bash Newbie: Looking for a script that can find numbers in txt-file and add=sum one number
Hello and greetings,
Decades ago I could script on DOS and with VB. Now on linux I want to get started with bash.
For CNC cutting, I have 3 gcode files. It's basicly a text file with coordinates X,Y and Z.
They all assume X0,Y0 in the down left corner, as you are supposed to cut them one after another.
I have a bigger CNC and want to cut them all in one go, so I need to add 300 to every existing X coordinate in the fist file and 600 to the second file.
The format of X is 1,2 or 3 before the digit. Like: X97.4606 so I need to make that X397.4606
So I guess I need to open the file for editing, find the number that is between X and. and add 300 to that number. A loop going through all lines till the end and closing.
it depends much on the structure of the source file (show us?).
i'm guessing that besides bash, you will need command line tools like sed, grep, awk...
awk and perl are scripting languages in their own right and might even be more suited for the job.
open your favorite search engine and enter "beginners tutorial $language" and replace $language with any of the terms i just mentioned.
Thanks for the reply, guess I would have python as an other option. Thought bash could do it.
Here are some lines:
G71
G90
G00 Z5.000
G00 X0 Y0
G00 X300.7193 Y66.9583 Z5.0000 M05
M03 G01 Z-0.5000 F180.0
M03 G01 X300.7193 Y66.9583 Z-0.5000 F180.0
Y57.9583
X302.7193 Y59.9583
G00 Z5.0000 M05
G00 X269.4136 Y170.6276 M05
M03 G01 Z-0.5000 F180.0
M03 G01 X269.4136 Y170.6276 Z-0.5000 F180.0
X269.2757 Y170.9796
X269.1044 Y171.3266
X268.8997 Y171.6641
X268.6621 Y171.9874
X268.3932 Y172.2918
X268.0955 Y172.5729
X267.7720 Y172.8268
X267.4267 Y173.0501
X267.0640 Y173.2403
X266.6886 Y173.3955
X266.3057 Y173.5149
X265.9199 Y173.5987
X265.5361 Y173.6478
X265.1583 Y173.6637
X262.4083
X262.1676 Y173.6491
X261.9202 Y173.6032
X261.6721 Y173.5232
X261.4302 Y173.4082
Generally it would be cool if the script would ask: "What coordinate do you want to change, X,Y or Z? How much do you want to add or subtract?"
For the moment it will do if I can add 300 to every number after X and before the. (dot).
The challenge is how to catch if the number is X8, X88 or X888. The expected outcome would be X308,X388 and X1188.
@Habitual Wow, that's a great link and the resources are indeed overwhelming :-)
Since I don't even know what tool to start with, I have no Pseudo Code.
I would like to cut the model boat on the CNC tomorrow. Learning any language in one night, starting with "Hello World" is a little tough.
I might have a Virtual Machine with Excel and could get it done with the VBA in there, but that would be a step backwards.
As far as I remember you would open the file and read each line as a string, search for X, store that position, search for the next .(dot), get that position. Between those, is the number you want to add 300 too.
What tool or combination would you suggest for this job?
You wish - there are nuances I'm still finding.
Try this to munge (only) the integer portion of the X values. Awk has an "interesting" attitude to real number manipulation, which has some unexpected results in seemingly random iterations. Usually when you really want exact answers.
Code:
awk '{where=match($0, /(.*X)([[:digit:]]+)(.*)/, a) ; if (where) {print a[1](a[2]+300)a[3]} else print}' cnc.txt
@syg00 Thank you so much!!! I added " > cnc-mod.txt " at the end and 1259 lines of gcode processed so fast, that I thought it did nothing. I knew linux would have a tool like that. Lots of learning to do, but a great starting point. Thanks all! Oh and yes, if there is an 'X', there is only 1 per line.
Offtopic: Thanks to you I will be happily chipping wood on the MaslowCNC. An interesting opensource project. Firmware code for the Arduino is C or C+ i think. Software is in python and kivy.
Edit: The final code used was:
Code:
awk '{where=match($0, /(.*X)([[:digit:]]+)(.*)/, a) ; if (where) {print a[1](a[2]+300)a[3]} else print}' cnc.txt > cnc-mod.txt
Last edited by geroBH; 08-05-2017 at 01:29 AM.
Reason: Adding the final line of code I used
Welcome to GNU/Linux and LQ, and compliments on a great beginning!
As others seem to have put your feet on a good path I have nothing better to add.
It would be helpful if you could edit your posts to place your code snippets inside [CODE]...[/CODE] tags for better readability. You may type those yourself or click the "#" button in the edit controls.
For the moment it will do if I can add 300 to every number after X and before the. (dot).
The challenge is how to catch if the number is X8, X88 or X888. The expected outcome would be X308,X388 and X1188.
Couldn't keep my hands off this.
Here is an altered example file. Look at the entries in bold:
#!/usr/bin/env python3
with open("X.txt") as infile:
for line in infile:
# Get the lines starting with 'X8*'
if line.startswith("X8"):
# Split into list
splitLine = line.split()
# Extract the digits and the dot
digits = splitLine[0].strip("X")
# Add 300 to the value
newValue = float(digits) + 300
# Keep it to 4 decimals
newValue = round(newValue, 4)
# Replace the old value in the list with the new
splitLine[0] = "X" + str(newValue)
# Join the list back to string
updatedLine = " ".join(splitLine)
# Print it!
print(updatedLine)
else:
print(line, end="")
Generally it would be cool if the script would ask: "What coordinate do you want to change, X,Y or Z? How much do you want to add or subtract?"
EDIT: I changed it a bit, it can now adjust multiple values at the same time, with multiple files.
Thought I'd take a go. You may only add or subtract (not divide or multiply)
The heavy worker in all this code is the regular expressions. (.*?)({direction})([-]*\d+[.]?\d+)(.*) will place this string into 4 groups -> 'X200.000 Y500.00' -> (X200.000) (Y) (500.00) ()
This allows you to easily add the Y and recombine the line.
Breakdown: (.*?) = matches everything upto the next match if existing. {direction} = variable you put in (eg x or X) ([-]*\d+[.]?\d+) = Match negative if there, match one or more digits, match . if there, match digits if there. (.*) = greedily match everything else (if there is anything else)
Quote:
For the moment it will do if I can add 300 to every number after X and before the. (dot).
In python, this is also known as a float. For example: 32.5
When the language you're using knows it's a float (or a decimal number), it's a lot easier to do operations on it, like adding or subtracting.
Making sure you only match the float right after a axis (X, Y, Z) is where regular expressions comes in.
./xyz_change.py -h
usage: xyz_change.py [-h] -f FILE [-c CHANGE]
Add or Subtract values starting with direction N
optional arguments:
-h, --help show this help message and exit
-f FILE, --file FILE Read file. Will print out changed portion
-c CHANGE, --change CHANGE
N [-+] Value eg. X +200 | Y+200 | Z -400
#!/usr/bin/env python3
from __future__ import print_function
import re
import sys
import argparse
# Capture command line arguments
parser = argparse.ArgumentParser(description='Add or Subtract values starting with direction N')
parser.add_argument('-f', '--file',
type=str,
required=True,
action='append',
help='Read file. Will print out changed portion')
parser.add_argument('-c', '--change',
type=str,
required=False,
help='N [-+] Value eg. X +200 | Y+200 | Z -400')
args, other_args = parser.parse_known_args()
def numbered(direction_nums, string):
for direction, number, *_ in direction_nums:
search = re.compile('(.*?)({direction})([-]*\d+[.]?\d*)(.*)'.format(
direction=direction.upper()))
match = search.match(string)
if match:
match = list(match.groups())
match[2] = str(float(match[2]) + float(number))
string = ''.join(match)
return string.strip()
# Capture X Y or Z and value to change by
input_change = re.compile('([a-zA-Z]{1})[\w\s]*?([+-]*\d+)')
direction_nums = ''.join(args.change) if args.change else str(other_args)
direction_nums = input_change.findall(direction_nums)
for _file in args.file:
with open(_file) as f:
for line in f.readlines():
print(numbered(direction_nums, line))
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.