Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Writing a bash script without using awk?

We are asked to write a shell script which takes in input of player records as standard inputs.

Sample input :

id|name|time
23|Jordan|45:17
14|Jason|4:50
12|Bryan|
24|Cody|00:12
33|kobe|41
55|rocky|0

And we need to read each record(skip header) in our script and then output each corresponding record by converting time in seconds and changing delimiter from '|' to ' '(space).

As we can see in above sample testcase, some records have empty time field(3rd record), for those record time in seconds will be considered 0.

Sample Case Output :

23 Jordan 2717
14 Jason 290
12 Bryan 0
24 Cody 12
33 kobe 2460
55 rocky 0

my_solution_script.sh

#!/bin/bash


read -r header
while IFS="|" read -r pid pname time || [[ -n $pid ]]
do  
    min=$(cut -d ':' -f 1 <<< "$time")
    sec=$(cut -d ':' -f 2 <<< "$time")
    ((min*=60))
    ((min+=sec))
    
    echo "$pid $pname $min"
done

Wrong Output :

23 Jordan 2717
14 Jason 290
12 Bryan 0
24 Cody 12
33 kobe 2501
55 rocky 0

As we can see above script is giving wrong output for 5th record.

How can I fix the above script, to get the correct output in every case?

I think there might be a simpler solution possible using awk, but I don't have much idea about 'awk scripting' right now, so I am looking for a way to solve this question using basic shell commands, nevertheless awk command solutions are also welcome.

Thank You.

like image 934
tusharRawat Avatar asked Jun 13 '26 19:06

tusharRawat


2 Answers

The problem is that cut -d: -f2 <<< "$time" returns all of $time when it doesn't contain a : delimiter. So for kobe you're calculating 41*60+41 instead of just 41*60.

So you need to check whether $time contains a : before trying to get the seconds.

read -r header
while IFS="|" read -r pid pname time || [[ -n $pid ]]
do  
    min=$(cut -d ':' -f 1 <<< "$time")
    if [[ $time =~ : ]]
        sec=$(cut -d ':' -f 2 <<< "$time")
    else
        sec=0
    fi
    ((min*=60))
    ((min+=sec))
    
    echo "$pid $pname $min"
done
like image 50
Barmar Avatar answered Jun 15 '26 11:06

Barmar


With GNU awk:

awk 'NR>1{$3=$3*60+$4; NF=3; print}' FS='[|:]' file

Output:

23 Jordan 2717
14 Jason 290
12 Bryan 0
24 Cody 12
33 kobe 2460
55 rocky 0

NF=3 limits GNU awk's print to three columns.


See: 8 Powerful Awk Built-in Variables – FS, OFS, RS, ORS, NR, NF, FILENAME, FNR

like image 31
Cyrus Avatar answered Jun 15 '26 10:06

Cyrus