0
#/bin/bash
sort(){
    for ((i = 0; i<$n; i++)) 
    do

        for((j = 0; j<`expr $n - $i - 1`; j++)) 
        do

        if [ ${arrival_time[j]} -gt ${arrival_time[$((j+1))]} ] 
        then
            # swap 
            temp=${arrival_time[j]} 
            arrival_time[$j]=${arrival_time[$((j+1))]}   
            arrival_time[$((j+1))]=$temp 
            temp=${burst_time[j]} 
            burst_time[$j]=${burst_time[$((j+1))]}   
            burst_time[$((j+1))]=$temp
            temp=${pid[j]} 
            pid[$j]=${pid[$((j+1))]}   
            pid[$((j+1))]=$temp
        elif [ ${arrival_time[j]} -eq ${arrival_time[$((j+1))]} ]
        then
            if [ ${pid[j]} -eq ${pid[$((j+1))]} ]
            then
                temp=${arrival_time[j]} 
                arrival_time[$j]=${arrival_time[$((j+1))]}   
                arrival_time[$((j+1))]=$temp 
                temp=${burst_time[j]} 
                burst_time[$j]=${burst_time[$((j+1))]}   
                burst_time[$((j+1))]=$temp
                temp=${pid[j]} 
                pid[$j]=${pid[$((j+1))]}   
                pid[$((j+1))]=$temp
            fi
        fi
        done
    done
}

border(){
    z=121
    for ((i=0; i<$z; i++))
    do
    echo -n "-"
    done
    echo ""
}

findWaitingTime(){
    service_time[0]=0
    waiting_time[0]=0
    for ((i=1; i<$n; i++))
    do
        z=1
        y=`expr $i - $z`
        service_time[$i]=`expr ${service_time[$y]} + ${burst_time[$y]} `
        waiting_time[$i]=`expr ${service_time[$i]} - ${arrival_time[$i]}`
        if [ ${waiting_time[$i]} -lt 0 ]
        then
            waiting_time[$i]=0
        fi
    done
}

findTurnAroundTime(){
    for ((i=0; i<$n; i++))
    do
        tat[$i]=`expr ${waiting_time[$i]} + ${burst_time[$i]}`
    done
}

findAverageTime(){
    sort
    findWaitingTime
    findTurnAroundTime
    total_wt=0
    total_tat=0
    border
    printf "|%-18s|%-20s|%-18s|%-20s|%-18s|%-20s|\n" "Process Id" "Burst time" "Arrival time" "Waiting time" "Turn around time" "Completion time"
    border
    for ((i=0; i<$n; i++))
    do
        total_wt=`expr $total_wt + ${waiting_time[$i]}`
        total_tat=`expr ${tat[$i]} + $total_tat`
        completion_time=`expr ${arrival_time[$i]} + ${tat[$i]}`
        printf "|%-18s|%-20s|%-18s|%-20s|%-18s|%-20s|\n" ${pid[$i]} ${burst_time[$i]} ${arrival_time[$i]} ${waiting_time[$i]} ${tat[$i]} $completion_time
        #echo "${burst_time[$i]}     ${arrival_time[$i]}     ${waiting_time[$i]}       ${tat[$i]}         $completion_time"
    done
    border
    #avgwt=`echo "scale=3; $total_wt / $n" | bc`
    echo -n "Average waiting time ="
    printf %.3f\\n "$(($total_wt / $n))"
    #avgtat=`echo "scale=3; $total_tat / $n" | bc`
    echo -n "Average turn around time ="
    printf %.3f\\n "$(($total_tat / $n))"

    for ((i=0; i<8*n+n+1; i++))
    do
        echo -n "-"
        done
        echo ""

    for ((i=0; i<$n; i++))
    do
        echo -n "|   "
        echo -n "P${pid[$i]}"
        echo -n "   "
    done
    echo "|"
    for ((i=0; i<8*n+n+1; i++))
    do
        echo -n "-"
        done
        echo ""
    echo -n "0  "
    for ((i=0; i<$n; i++))
    do
        echo -n "`expr ${arrival_time[$i]} + ${tat[$i]}`"
        echo -n "      "
    done
    echo ""
}


n=$(sed -e '1~2d' fcfs1.txt |awk '{ for (i=1; i<=NF; i++) RtoC[i]= (i in RtoC?RtoC[i] OFS :"") $i; } END{ for (i=1; i<=NF; i++) print RtoC[i] }'| awk '{print $1}' |wc -l)
for ((i=0; i<$n; i++))
do
pid[$i]=$(cat fcfs.txt | awk '{print $1}')
arrival_time[$i]=$(cat fcfs.txt | awk '{print $2}')
burst_time[$i]=$(cat fcfs.txt | awk '{print $3}')
done
findAverageTime

fcfs.txt content is like this:

1  15  10
2   17  12

if input file has only one process script working perfect, if more that one gives an error output when only one process in the input file

-------------------------------------------------------------------------------------------------------------------------
|Process Id        |Burst time          |Arrival time      |Waiting time        |Turn around time  |Completion time     |
-------------------------------------------------------------------------------------------------------------------------
|1                 |5                   |10                |0                   |5                 |15                  |
-------------------------------------------------------------------------------------------------------------------------
Average waiting time =0.000
Average turn around time =5.000
----------
|   P1   |
----------
0   15     
muru
  • 72,889
  • 1
    Always paste your script into https://shellcheck.net, a syntax checker, or install shellcheck locally. Make using shellcheck part of your development process. – waltinator Jun 26 '22 at 00:41
  • 1
    Could you share the documentation that specifies the input and ouputs of the script? "create a first come first served" is a very poor description. By "first", do mean earliest arrival or lowest timestamp? – waltinator Jun 26 '22 at 00:48
  • 1
    Whatever this is supposed to do, you would be better off re-writing it in awk or perl. or python. or almost anything except shell. There are a lot of calculations, which is definitely not one of bash's strengths (and bash can only do integer arithmetic anyway, but you seem to be expecting floating point results for some of your calcs). – cas Jun 26 '22 at 07:42
  • @waltinator i already added the input file fcfs.txt contains pid, arrival time & burst time.... output will be like last part pid, AT, BT, Waiting time & turn around time.. yes based on earlist arrival -- arrival time – peter louis Jun 26 '22 at 09:52
  • calculation are as following: wt=st-at || wt=tt-bt || tt=ct-at – peter louis Jun 26 '22 at 09:57
  • @cas okay thanks, but it's working with only one pid, but when i add two or mores pid it gives an errors – peter louis Jun 26 '22 at 10:00
  • 1
    That's because your script just cats the entire input file and pipes it into awk to extract values (multiple times, once for each value it wants to extract). It doesn't even attempt to iterate over each line with a while-read loop. And before you go ahead and do that, I suggest you read Why is using a shell loop to process text considered bad practice?. BTW, I'm not saying "don't use shell" because I want to make things more difficult for you - quite the opposite, I want to point you in a direction where what you're doing will be trivially easy. – cas Jun 26 '22 at 10:10
  • 2
    And that direction is "use a better language, one that's actually suited to what you're trying to do". awk would be a good choice. As would perl. Almost any language that isn't shell would be a better choice for what you're trying to do. Shell is a good language for co-ordinating the execution of other programs to do work like processing text or calculating averages or whatever. It's absolutely terrible at trying to do that work itself. – cas Jun 26 '22 at 10:13
  • A shell is a tool to manipulate (create/destroy) files and processes and sequence calls to other tools. It's not a tool to manipulate text as you're trying to do in your script. Manipulating text is the one thing awk exists to do (and there are other tools that can manipulate text). Right now it's kinda like you're trying to drill a hole using the bag your tools come in instead of the drill sitting in your bag. If you [edit] your question to tell us what it is you're trying to to then we can help you (we can't tell what you want to do by reading a script that doesn't do what you want to do). – Ed Morton Jun 26 '22 at 23:17

1 Answers1

1

Here's an example of the kind of thing you can do easily with perl, to show you WHY you should learn a better language for processing text. Your original shell script seems to be around 128 lines of code and doesn't work (or have any comments describing how it's supposed to work). This perl script is around 57 lines (not counting about 30 lines of comments).

I've attempted to figure out the correct calculations for each row as best I can, but it's entirely likely that I've made some mistakes - your script is over-complicated (very much so) and repetitive, and it is difficult to understand what it's doing or why it's doing something. Feel free to correct the script below, or let me know what the correct calculations should be.

$ cat summarise_fcfs.pl
#!/usr/bin/perl

use strict;

Construct the format string for printf. and the ruler line too.

Width of each field is just enough to fit its header plus a space on

both sides.

#my @headers = ("Process ID", "Burst time", "Arrival time",

"Waiting time", "Turn around time", "Completion time");

Shorter headers to fit in "standard" 80-column terminal

my @headers = ("Process ID", "Burst", "Arrival", "Waiting", "Turnaround", "Completion");

my $fmt = '|'; my $ruler = '|'; foreach (@headers) { my $len = length($_); $fmt .= " %${len}s |"; $ruler .= '-' x ($len + 2) . '|'; }; $fmt .= "\n"; $ruler .= "\n";

my $total_wait = 0; my $total_tat = 0;

@data is an Array-of-Arrays (AoA) data structure to hold the values

for each PID. Also known as a List-of-Lists or LoL. See `man

perllolandman perldsc` for details.

my @data = ();

@st is a single-dimensional array to hold the service time values

for each PID. These aren't going to be printed with the printf

format string, so are kept separately from @data (it's easier than

extracting an array slice from @data to print for each row)

my @st = ();

Record counter

my $i = 0;

while(<>) { chomp; s/^\s|\s$//g; # strip leading and trailing whitespace s/#.//; # strip comments if any next if /^\s$/; # skip empty lines

my ($pid, $arrival, $burst) = split;

my $st = 0; if ($i > 0) { # previous st + previous burst $st = $st[$i-1] + $data[$i-1][1] };

my $wait = $st - $arrival; $wait = 0 if ($wait < 0); my $tat = $wait + $burst; my $completion = $arrival + $tat;

Store the data for the current PID in the @data AoA.

$data[$i] = [ $pid, $burst, $arrival, $wait, $tat, $completion ];

and store the service time too

$st[$i] = $st;

keep track of totals and increment the record counter.

$total_wait += $wait; $total_tat += $tat;

$i++; };

All data has been read and processed, now it's time

to produce some output.

print $ruler, sprintf($fmt, @headers), $ruler;

sort by arrival time (element 2 of each array in

@data). Like bash, perl array indices start from zero.

foreach my $row (sort { $data[$a][2] <=> $data[$b][2] } keys @data) { printf $fmt, @{ $data[$row] }; };

print $ruler, "\n";

printf "Average waiting time = %.3f\n", $total_wait / $i; printf "Average turn around time = %.3f\n\n", $total_tat / $i;

Now print a table of completion times (5th element of @data[$row])

for each PID. Limit to 8 columns (PIDs) per output line so it

doesn't get ridiculously wide.

my $step = 8; # max number of PIDs per output row for (my $start_col = 0; $start_col < $i ; $start_col += $step) { my $end_col = $start_col + $step - 1; $end_col = $i-1 if $end_col > $i;

Rebuild headers and ruler line for each $step number of PIDs

my @P_headers = map { "P" . $data[$_][0] } $start_col..$end_col; my $P_fmt = '|'; my $P_ruler = '|';

foreach (@P_headers) { #my $len = length($_)+4; my $len = 6; # is 6 characters enough for the PID? $P_fmt .= " %${len}s |"; $P_ruler .= '-' x ($len + 2) . '|'; }; $P_fmt .= "\n"; $P_ruler .= "\n";

and print the current row

print $P_ruler, sprintf($P_fmt, @P_headers), $P_ruler; printf $P_fmt, map { $data[$_][5] } $start_col..$end_col; print $P_ruler, "\n"; }

Sample output:

$ ./summarise_fcfs.pl fcfs.txt 
|------------|-------|---------|---------|------------|------------|
| Process ID | Burst | Arrival | Waiting | Turnaround | Completion |
|------------|-------|---------|---------|------------|------------|
|          1 |    10 |      15 |       0 |         10 |         25 |
|          2 |    12 |      17 |       0 |         12 |         29 |
|------------|-------|---------|---------|------------|------------|

Average waiting time = 0.000 Average turn around time = 11.000

|--------|--------| | P1 | P2 | |--------|--------| | 25 | 29 | |--------|--------|

cas
  • 78,579