Home > Software design >  recursive awk in bash script
recursive awk in bash script

Time:05-08

I am trying to make a recursive awk. The goal is to be able to ask for 4 and get 4 5 6 7

The testfile.csv looks like this:

From,To
2,3
1,2
4,5
3,4
5,6
6,7
0,1

My awk code works if I leave out the recursive part, but when I run this:

#!/bin/bash

path()
{
    if [ -z "$1" ]; then
       echo " _"
    else
        last= $(path $(awk -v myvar="$1" -F"," '$1 ~ myvar { print $2 }' testfile.csv))
        echo $(( last ))
    fi
}
path $1

All I get is:

$ bash path 4
path: line 8: awk -v myvar=4 -F, '4 ~ myvar { print  }' testfile.csv: syntax error in expression (error token is "myvar=4 -F, '4 ~ myvar { print  }' testfile.csv")
0

I've read all I can find on the subject. I can do the awk or the recursion, but I can't get them to work together.

Any ideas? Thank you

CodePudding user response:

An efficient, robust, portable way to do what you want would be:

path() {
    awk -v cur="$1" '
        BEGIN { FS="," }
        { map[$1] = $2 }
        END {
            out = cur
            while ( cur in map ) {
                nxt = map[cur]
                out = out OFS nxt
                delete map[cur]
                cur = nxt
            }
            print out
        }
    ' testfile.csv
}

path 4
4 5 6 7

That would be orders of magnitude faster than using a recursive shell function. The delete map[cur] is to protect against infinite recursion in your data, e.g. 4,5 and 5,4.

CodePudding user response:

To complement what Ed wrote, here is a pure bash implementation:

#!/usr/bin/env bash

declare -a map=()

while IFS=, read -r k v; do
  map[k]=$v
done

ppat () {
  cur=$1
  local -a out=("$cur")
  while [[ -v map["$cur"] ]]; do
    nxt=${map[$cur]}
    out =("$nxt")
    unset map["$cur"]
    cur=$nxt
  done
  printf '%s\n' "${out[*]}"
}

ppat "$1"

Usage example:

$ bash script.sh 4 < testfile.csv
4 5 6 7
  • Related