monolith937
monolith937

Reputation: 459

shell script subtract fields from pairs of lines

Suppose I have the following file:

stub-foo-start: 10
stub-foo-stop: 15
stub-bar-start: 3
stub-bar-stop: 7
stub-car-start: 21
stub-car-stop: 51
# ... 
# EOF at the end

with the goal of writing a script which would append to it like so:

stub-foo-start: 10
stub-foo-stop: 15
stub-bar-start: 3
stub-bar-stop: 7
stub-car-start: 21
stub-car-stop: 51
# ...
# appended: 
stub-foo: 5        # 5 = stop(15) - start(10)
stub-bar: 4        # and so on... 
stub-car: 30
# ...
# new EOF 

The format is exactly this sequential pairing of start and stop tags (stop being the closing one) and no nesting in between.

What is the recommended approach to writing such a script using awk and/or sed? Mostly, what I've tried is greping lines, storing to a variable, but that seemed to overcomplicate things and trail off.

Any advice or helpful links welcome. (Most tutorials I found on shell scripting were illustrative at best)

Upvotes: 0

Views: 136

Answers (2)

M. Nejat Aydin
M. Nejat Aydin

Reputation: 10123

A naive implementation in plain bash

#!/bin/bash

while read -r start && read -r stop; do
    printf '%s: %d\n' "${start%-*}" $(( ${stop##*:} - ${start##*:} )) 
done < file

This assumes pairs are contiguous and there are no interlaced or nested pairs.

Upvotes: 2

Raman Sailopal
Raman Sailopal

Reputation: 12877

Using GNU awk:

awk -F '[ -]' '{ map[$2][$3]=$4;print } END { for (i in map) { print i": "(map[i]["stop:"]-map[i]["start:"])" // ("map[i]["stop:"]"-"-map[i]["start:"]")" } }' file

Explanation:

awk -F '[ -]' '{                                                       # Set the field delimiter to space or "-"
                 map[$2][$3]=$4;                                       # Create a two dimensional array with the second and third field as indexes and the fourth field as the value
                 print                                                 # Print the line
               } 
           END { for (i in map) { 
                 print i": "(map[i]["stop:"]-map[i]["start:"])" // ("map[i]["stop:"]"-"-map[i]["start:"]")"                                                      # Loop through the array and print the data in the required format
                 } 
                }' file

Upvotes: 1

Related Questions