LinuxQuestions.org
Latest LQ Deal: Linux Power User Bundle
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 08-04-2017, 05:25 AM   #1
geroBH
LQ Newbie
 
Registered: Aug 2017
Posts: 5

Rep: Reputation: Disabled
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.

Any help to get started is highly appreciated.
 
Old 08-04-2017, 05:41 AM   #2
syg00
LQ Veteran
 
Registered: Aug 2003
Location: Australia
Distribution: Lots ...
Posts: 15,795

Rep: Reputation: 2157Reputation: 2157Reputation: 2157Reputation: 2157Reputation: 2157Reputation: 2157Reputation: 2157Reputation: 2157Reputation: 2157Reputation: 2157Reputation: 2157
Going to be interesting in bash. Post some real data, and the expected output - just a few lines so we are all on the same page.
 
1 members found this post helpful.
Old 08-04-2017, 06:02 AM   #3
ondoho
LQ Addict
 
Registered: Dec 2013
Posts: 6,172
Blog Entries: 2

Rep: Reputation: 1487Reputation: 1487Reputation: 1487Reputation: 1487Reputation: 1487Reputation: 1487Reputation: 1487Reputation: 1487Reputation: 1487Reputation: 1487
Quote:
Originally Posted by geroBH View Post
Any help to get started is highly appreciated.
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.

for bash:
https://www.gnu.org/software/bash/manual/
 
1 members found this post helpful.
Old 08-04-2017, 06:02 AM   #4
geroBH
LQ Newbie
 
Registered: Aug 2017
Posts: 5

Original Poster
Rep: Reputation: Disabled
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.
 
Old 08-04-2017, 06:42 AM   #5
Habitual
LQ Addict
 
Registered: Jan 2011
Posts: 8,555
Blog Entries: 13

Rep: Reputation: Disabled
### Bash Programming/Coding ### section.
should a generalized search prove overwhelming?

Pseudo Code should be agnostic. Have any?
 
1 members found this post helpful.
Old 08-04-2017, 06:51 AM   #6
hazel
Senior Member
 
Registered: Mar 2016
Location: Harrow, UK
Distribution: Debian, Crux, LFS, AntiX, NuTyX
Posts: 1,253
Blog Entries: 1

Rep: Reputation: 573Reputation: 573Reputation: 573Reputation: 573Reputation: 573Reputation: 573
I'd do a thing like that in awk, not bash.
 
Old 08-04-2017, 07:02 AM   #7
geroBH
LQ Newbie
 
Registered: Aug 2017
Posts: 5

Original Poster
Rep: Reputation: Disabled
@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?
 
Old 08-04-2017, 07:22 AM   #8
geroBH
LQ Newbie
 
Registered: Aug 2017
Posts: 5

Original Poster
Rep: Reputation: Disabled
Thanks for pointing at awk. A quick look at a beginners tutorial made me confident that I could learn that pretty fast.
 
Old 08-04-2017, 08:43 AM   #9
syg00
LQ Veteran
 
Registered: Aug 2003
Location: Australia
Distribution: Lots ...
Posts: 15,795

Rep: Reputation: 2157Reputation: 2157Reputation: 2157Reputation: 2157Reputation: 2157Reputation: 2157Reputation: 2157Reputation: 2157Reputation: 2157Reputation: 2157Reputation: 2157
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
Edit: presumes only one X??? value per line.

Last edited by syg00; 08-04-2017 at 08:46 AM.
 
3 members found this post helpful.
Old 08-04-2017, 11:48 AM   #10
geroBH
LQ Newbie
 
Registered: Aug 2017
Posts: 5

Original Poster
Rep: Reputation: Disabled
@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
 
Old 08-04-2017, 02:34 PM   #11
astrogeek
Moderator
 
Registered: Oct 2008
Distribution: Slackware [64]-X.{0|1|2|37|-current} ::12<=X<=14, FreeBSD_10{.0|.1|.2}
Posts: 4,454
Blog Entries: 6

Rep: Reputation: 2394Reputation: 2394Reputation: 2394Reputation: 2394Reputation: 2394Reputation: 2394Reputation: 2394Reputation: 2394Reputation: 2394Reputation: 2394Reputation: 2394
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.

Good luck with the boat!
 
1 members found this post helpful.
Old 08-05-2017, 09:29 AM   #12
HMW
Member
 
Registered: Aug 2013
Location: Sweden
Distribution: Debian, Arch, Red Hat, CentOS
Posts: 764
Blog Entries: 3

Rep: Reputation: 366Reputation: 366Reputation: 366Reputation: 366
Quote:
Originally Posted by geroBH View Post
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:
Code:
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
X8.6886 Y173.3955
X266.3057 Y173.5149
X265.9199 Y173.5987
X88.5361 Y173.6478
X265.5361 Y173.6478
X265.1583 Y173.6637
X262.4083
X888.1676 Y173.6491
X261.9202 Y173.6032
X261.6721 Y173.5232
X261.4302 Y173.4082
Now when I run this Python script:
Code:
#!/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="")
I get this result:
Code:
./readX.py 
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
X308.6886 Y173.3955
X266.3057 Y173.5149
X265.9199 Y173.5987
X388.5361 Y173.6478
X265.5361 Y173.6478
X265.1583 Y173.6637
X262.4083
X1188.1676 Y173.6491
X261.9202 Y173.6032
X261.6721 Y173.5232
X261.4302 Y173.4082
 
Old 08-06-2017, 03:50 AM   #13
ondoho
LQ Addict
 
Registered: Dec 2013
Posts: 6,172
Blog Entries: 2

Rep: Reputation: 1487Reputation: 1487Reputation: 1487Reputation: 1487Reputation: 1487Reputation: 1487Reputation: 1487Reputation: 1487Reputation: 1487Reputation: 1487
Quote:
Originally Posted by geroBH View Post
A quick look at a beginners tutorial made me confident that I could learn that pretty fast.
now THAT is something I'd like to read much more often here on LQ!
 
Old 08-06-2017, 10:11 AM   #14
Sefyir
Member
 
Registered: Mar 2015
Distribution: Linux Mint
Posts: 517

Rep: Reputation: 236Reputation: 236Reputation: 236
Python3 Program

Quote:
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.

This file uses some advanced features like regular expressions and argument parsing.

Code:
./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
Code:
./xyz_change.py -f xyfile -f xyfile2 -c X+200
...
X465.1583 Y173.6637
X462.4083
X462.1676 Y173.6491
X461.9202 Y173.6032
...
Code:
./xyz2_change.py -f xyfile X-10000 Y+4000
...
X-9734.4639 Y4173.6478
X-9734.8417 Y4173.6637
X-9737.5917
X-9737.8324 Y4173.6491
...


Code:
#!/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))

Last edited by Sefyir; 08-09-2017 at 10:06 AM.
 
Old 08-06-2017, 12:02 PM   #15
schneidz
LQ Guru
 
Registered: May 2005
Location: boston, usa
Distribution: fc-15/ fc-20-live-usb/ aix
Posts: 5,143

Rep: Reputation: 877Reputation: 877Reputation: 877Reputation: 877Reputation: 877Reputation: 877Reputation: 877
heres my try:
Code:
[schneidz@hyper gerobh]$ ./syg00.ksh 200 250 500 gerobh.lst
G71
G90
G00 Z505.000
G00 X200 Y250
G00 X500.7193 Y316.9583 Z505.0000 M05
M03 G01 Z-0.5000 F180.0
M03 G01 X500.7193 Y316.9583 Z-0.5000 F180.0
Y307.9583
X502.7193 Y309.9583
G00 Z505.0000 M05
G00 X469.4136 Y420.6276 M05
M03 G01 Z-0.5000 F180.0
M03 G01 X469.4136 Y420.6276 Z-0.5000 F180.0
X469.2757 Y420.9796
X469.1044 Y421.3266
X468.8997 Y421.6641
X468.6621 Y421.9874
X468.3932 Y422.2918
X468.0955 Y422.5729
X467.7720 Y422.8268
X467.4267 Y423.0501
X467.0640 Y423.2403
X466.6886 Y423.3955
X466.3057 Y423.5149
X465.9199 Y423.5987
X465.5361 Y423.6478
X465.1583 Y423.6637
X462.4083
X462.1676 Y423.6491
X461.9202 Y423.6032
X461.6721 Y423.5232
X461.4302 Y423.4082
[schneidz@hyper gerobh]$ cat syg00.ksh                  
#!/bin/bash

awk -v x=$1 '{where=match($0, /(.*X)([[:digit:]]+)(.*)/, a) ; if (where) {print a[1](a[2]+x)a[3]} else print}' $4 > syg00.x

awk -v x=$2 '{where=match($0, /(.*Y)([[:digit:]]+)(.*)/, a) ; if (where) {print a[1](a[2]+x)a[3]} else print}' syg00.x > syg00.y

awk -v x=$3 '{where=match($0, /(.*Z)([[:digit:]]+)(.*)/, a) ; if (where) {print a[1](a[2]+x)a[3]} else print}' syg00.y

rm syg00.x syg00.y
it doesnt work with the -z's.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
bash script to add integer values & get the sum demet8 Linux - Newbie 5 10-20-2012 01:46 PM
Bash script to compare numbers in a txt file leopard86 Programming 6 09-11-2012 12:10 AM
shell script to find the sum of numbers associated with each character in a string Aagam Linux - Newbie 22 02-07-2012 08:59 AM
how to add numbers in a formatted file via a bash script? zero79 Linux - General 8 12-24-2010 05:48 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 09:59 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration