3

I am trying to look a for some specific values from (such as 1 or 4 and 2 or 3) a text file using an awk statement in a bash script. If this value is found in the file (within the awk statement), then I want to call a function from outside the awk statement and pass it the found value as an argument.

My questions: (1) Is this possible? If so then how? (2) If it is not possible or there is a better way, then how?

Note that I am skipping the first two lines of the text file when searching the file. I am using GNU AWK. Let me know if further explanation is required.

**I apologize in advance for the cross-post but I did not get the answer I am looking for.

file.txt

Name  Col1  Col2  Col3  
-----------------------
row1  1     4     7        
row2  2     5     8         
row3  3     6     9 

The actual retrieve functions are much more complex than in this simplified example. So I need to make a call to this function because I don't want to put this in the awk statement.

function retrieve {
    if [[ "$1" == "1" ]]; then
        echo "one beer on the wall"
    elif [[ "$1" == "4" ]]; then
        echo "four beers on the wall"
    fi
}

function retrieve2 {
    if [[ "$1" == "2" ]]; then
        echo "two beers on the wall"
    elif [[ "$1" == "3" ]]; then
        echo "three beers on the wall"
    fi
}

awk -F '\t' '
    FNR < 2 {next}
    FNR == NR {
        for (i=2; i <= NF; i++) 
        {
            if (($i == 1) || ($i == 4))
                printf(%s, "'retrieve "$i" '")    # Here is the problem

            if (($i == 2) || ($i == 2))
                printf(%s, "'retrieve2 "$i" '")    # Here is the problem
        }
    }

' file.txt

closed as off-topic by jasonwryan, peterph, Michael Homer, John1024, Ramesh Jul 21 '14 at 23:10

This question appears to be off-topic. The users who voted to close gave this specific reason:

  • "This question has been posted on multiple sites. Cross-posting is strongly discouraged; see the help center and community FAQ for more information." – jasonwryan, peterph, Michael Homer, John1024, Ramesh

5

An ugly way of doing this (i.e. causing a function call in shell based on output from awk) could look like this:

awk -F '\t' '
    FNR < 2 {next}
    FNR == NR {
        for (i=2; i <= NF; i++) {
            if (($i == 1) || ($i == 4))
                printf "retrieve %s\n", $i

            if (($i == 2) || ($i == 2))
                printf "retrieve2 %s\n", $i
        }
    }

' file.txt | while read l; do eval $l; done

However this might seriously backfire in some cases.

  • Your approach is interesting, IF it's acceptable to call the functions AFTER awk has finished processing (in other words: if there's no need to interleave awk output with shell-function output). To avoid the eval security risk, you could try the following, assuming there are no quoted tokens (tokens with embedded whitespace) to deal with: ... | while read -ra args; do "${args[@]}"; done. If you do need to call the shell function from within awk, see stackoverflow.com/a/24875216/45375 – mklement0 Jul 21 '14 at 22:30
  • Well you can always pass the shell function $0 from awk as one of it's arguments, but it has to be properly quoted - which is exactly where it gets messy. The function exporting seems cleaner though. – peterph Jul 24 '14 at 22:49

Not the answer you're looking for? Browse other questions tagged or ask your own question.