ChangeJar
ChangeJar

Reputation: 163

String together awk commands

I'm writing a script that searches a file, gets info that it then stores into variables, and executes a program that I made using those variables as data. I actually have all of that working, but I need to take it a step further:

What I currently have is

    #!/bin/sh                                                                       
    START=0                                                                         
    END=9                                                                           
    LOOP=10                                                                         
    PASS=0                                                                          
    for i in $(seq 0 $LOOP)                                                         
    do                                                                              
        LEN=$(awk '/Len =/ { print $3; exit;}' ../../Tests/shabittestvectors/SHA1ShortMsg.rsp)
        MSG=$(awk '/Msg =/ { print $3; exit; }' ../../Tests/shabittestvectors/SHA1ShortMsg.rsp)
        MD=$(awk '/MD =/ { print $3; exit; }' ../../Tests/shabittestvectors/SHA1ShortMsg.rsp)

        echo $LEN                                                                   
        echo $MSG                                                                   
        MD=${MD:0:-1}                                                               
        CIPHER=$(./cyassl hash -sha -i $MSG -l $LEN)                                
        echo $MD                                                                    
        echo $CIPHER                                                                

        if [ $MD == $CIPHER ]; then                                                 
            echo "PASSED"                                                           
            PASS=$[PASS + 1]                                                        
            echo $PASS                                                              
        fi                                                                          
    done                                                                            
    if [ $PASS == $[LOOP+1] ]; then                                                 
        echo "All Tests Successful"                                                 
    fi

And the input file looks like this:

Len = 0
Msg = 00
MD = da39a3ee5e6b4b0d3255bfef95601890afd80709

Len = 1
Msg = 00
MD = bb6b3e18f0115b57925241676f5b1ae88747b08a

Len = 2
Msg = 40
MD = ec6b39952e1a3ec3ab3507185cf756181c84bbe2

All the program does right now, is read the first instances of the variables and loop around there. I'm hoping to use START and END to determine the lines in which it checks the file, and then increment them every time it loops to obtain the other instances of the variable names, but all of my attempts have been unsuccessful so far. Any ideas?

EDIT: Output should look something like, providing my program "./cyassl" works as it should

0
00
da39a3ee5e6b4b0d3255bfef95601890afd80709
da39a3ee5e6b4b0d3255bfef95601890afd80709
PASSED

1
00
bb6b3e18f0115b57925241676f5b1ae88747b08a
bb6b3e18f0115b57925241676f5b1ae88747b08a                    
PASSED

2
40
ec6b39952e1a3ec3ab3507185cf756181c84bbe2
ec6b39952e1a3ec3ab3507185cf756181c84bbe2
PASSED

etc.                      

Upvotes: 2

Views: 242

Answers (3)

clt60
clt60

Reputation: 63892

The following code,

inputfile="../../Tests/shabittestvectors/SHA1ShortMsg.rsp"

while read -r len msg md
do
        echo got: LEN:$len  MSG:$msg MD:$md

        #cypher=$(./cyassl hash -sha -i $msg -l $len)
        #continue as you wish

done < <(perl -00 -F'[\s=]+|\n' -lE 'say qq{$F[1] $F[3] $F[5]}' < "$inputfile")

for your input data, produces:

got: LEN:0 MSG:00 MD:da39a3ee5e6b4b0d3255bfef95601890afd80709
got: LEN:1 MSG:00 MD:bb6b3e18f0115b57925241676f5b1ae88747b08a
got: LEN:2 MSG:40 MD:ec6b39952e1a3ec3ab3507185cf756181c84bbe2

Upvotes: 2

William Pursell
William Pursell

Reputation: 212148

There's no need to make multiple passes on the input file.

#!/bin/sh
exec < ../../Tests/shabittestvectors/SHA1ShortMsg.rsp
status=pass
awk '{print $3,$6,$9}' RS= | {
while read len msg md; do
    if test "$(./cyassl hash -sha -i $msg -l $len)" = "$md"; then
        echo passed
    else
        status=fail
    fi
done
test "$status" = pass && echo all tests passed
}

The awk will read from stdin (which the exec redirects from the file; personally I would skip that line and have the caller direct input appropriately) and splits the input into records of one paragraph each. A "paragraph" here means that the records are separated by blank lines (the lines must be truly blank, and cannot contain whitespace). Awk then parses each record and prints the 3rd, 6th, and 9th field on a single line. This is a bit fragile, but for the shown input those fields represent length, message, and md hash, respectively. All the awk is doing is rearranging the input so that it is one record per line. Once the data is in a more readable format, a subshell reads the data one line at a time, parsing it into the variables named "len", "msg", and "md". The do loop processes once per line of input, spewing the rather verbose message "passed" with each test it runs (I would remove that, but retained it here for consistency with the original script), and setting the status if any tests fail. The braces are necessary to ensure that the value of the variable status is retained after the do loop terminates.

Upvotes: 3

konsolebox
konsolebox

Reputation: 75458

If your input data is in order you can have this with a simplified bash:

#!/bin/bash

LOOP=10
PASS=0

FILE='../../Tests/shabittestvectors/SHA1ShortMsg.rsp'

for (( I = 1; I <= LOOP; ++I )); do
    read -r LEN && read -r MSG && read -r MD || break

    echo "$LEN"
    echo "$MSG"

    MD=${MD:0:-1}
    CIPHER=$(exec ./cyassl hash -sha -i "$MSG" -l "$LEN")

    echo "$MD"
    echo "$CIPHER"

    if [[ $MD == "$CIPHER" ]]; then
        echo "PASSED"
        (( ++PASS ))
    fi
done < <(exec awk '/Len =/,/Msg =/,/MD =/ { print $3 }' "$FILE")

[[ PASS -eq LOOP ]] && echo "All Tests Successful."

Just make sure you don't run it as sh e.g. sh script.sh. bash script.sh most likely.

Upvotes: 1

Related Questions