Bash script time script

I have the following code which i'd like to rewrite in a way that it can be used on all unix systems. meaning, i want it to be portable:

# turn seconds into real measurable time

                                            num=$1
                                            min=0
                                            hour=0
                                            day=0
                                            if((num>59));then
                                                ((sec=num%60))
                                                ((num=num/60))
                                                if((num>59));then
                                                    ((min=num%60))
                                                    ((num=num/60))
                                                    if((num>23));then
                                                        ((hour=num%24))
                                                        ((day=num/24))
                                                    else
                                                        ((hour=num))
                                                    fi
                                                else
                                                    ((min=num))
                                                fi
                                            else
                                                ((sec=num))
                                            fi
                                            echo "$day"d,"$hour"h,"$min"m,"$sec"s
                                      

the shell i intend to use is basic shell..i.e. /bin/sh but as many of you can tell already, the above is written in newer form of bash which is simply not available on some systems.

This would be the POSIX equivalent of you bash snippet, which should also run correctly in bash itself.
Give this a try:

                                            num=$1
                                            min=0 hour=0 day=0
                                            if [ $num -gt 59 ]; then
                                                sec=$((num%60))
                                                num=$((num/60))
                                                if [ $num -gt 59 ];then
                                                    min=$((num%60))
                                                    num=$((num/60))
                                                    if [ $num -gt 23 ];then
                                                        hour=$((num%24))
                                                        day=$((num/24))
                                                    else
                                                        hour=$num
                                                    fi
                                                else
                                                    min=$num
                                                fi
                                            else
                                                sec=$num
                                            fi
                                            printf "%dd,%dh,%dm,%ds\n" "$day" "$hour" "$min" "$sec"

--
Note: on Solaris use /usr/xpg4/bin/sh ( /bin/sh on Solaris is the Bourne shell, which is not POSIX compliant and cannot run this code)

--
Note: echo "$day"d,"$hour"h,"$min"m,"$sec"s should probably work too, but printf is the standardized way in POSIX

1 Like

i tried this on aix and it didnt work:

$ uname -a
AIX pnim01 3 5 00CD78AD4C00
$ 
$ cat mytime.sh
#!/bin/sh

num=5600
                                            min=0 hour=0 day=0
                                            if [ $num -gt 59 ]; then
                                                sec=$((num%60))
                                                num=$((num/60))
                                                if([ $num -gt 59 ];then
                                                    min=$((num%60))
                                                    num=$((num/60))
                                                    if([ $num -gt 23 ];then
                                                        hour=$((num%24))
                                                        day=$((num/24))
                                                    else
                                                        hour=$num
                                                    fi
                                                else
                                                    min=$num
                                                fi
                                            else
                                                sec=$num
                                            fi
                                            echo "$day"d,"$hour"h,"$min"m,"$sec"s
$ 
$ 
$ ./mytime.sh  
./mytime.sh[5]: 0403-057 Syntax error at line 9 : `then' is not expected.

Yes, I was still in the process of editing my code when you copy/pasted it. Try the code as it is now in post #2 again

if([ $num -gt 59 ];then

Remove that `(' from the ifs. There are several.

1 Like

Note also that:

                                            min=0 hour=0 day=0

should be changed to either:

                                            min=0;hour=0;day=0

or:

                                            min=0
                                            hour=0
                                            day=0
1 Like

Hi Don,

From the Shell Command Language: Shell Grammar Rules:

simple_command   : cmd_prefix cmd_word cmd_suffix
                 | cmd_prefix cmd_word
                 | cmd_prefix
                 | cmd_name cmd_suffix
                 | cmd_name
[..]
cmd_prefix       :            io_redirect
                 | cmd_prefix io_redirect
                 |            ASSIGNMENT_WORD
                 | cmd_prefix ASSIGNMENT_WORD

So I do not understand why this could be a problem. It certainly works fine wherever I try it.

2 Likes

Hi Scrutinizer,
Yes, I apologize. Before the standards were there for the shell, at least one shell treated the simple command:

a=1 b=2 c=3

as the command c=3 with the other two assignments being treated as a command prefix (so a and b did not end up being present in the current shell execution environment; they were only available in the execution environment of the assignment command assigning a value to c ). I don't remember if any shell still has this strange behavior, but since we're talking about POSIX shells in this thread it doesn't matter. With any POSIX conforming shell all three of the following produce the same results:

a=1 b=2 c=3
a=1;b=2;c=3
a=1
b=2
c=3
2 Likes

thanks everyone. it works now! :slight_smile:

This should be basic /bin/sh compatible

#!/bin/sh

# turn seconds into real measurable time

num=${1:-0}
min=0
hour=0
day=0
if [ $num -gt 59 ]
then
    sec=`expr $num % 60`
    num=`expr $num / 60`
    if [ $num -gt 59 ]
    then
        min=`expr $num % 60`
        num=`expr $num / 60`
        if [ $num -gt 23 ]
        then
            hour=`expr $num % 24`
            day=`expr $num / 24`
        else
            hour=$num
        fi
    else
        min=$num
    fi
else
    sec=$num
fi
echo "$day"d,"$hour"h,"$min"m,"$sec"s

or it could be simplified a little (at the expense of some performance):

#!/bin/sh

# turn seconds into real measurable time

num=${1:-0}
day=`expr $num / 86400`
num=`expr $num % 86400`
hour=`expr $num / 3600`
num=`expr $num % 3600`
min=`expr $num / 60`
sec=`expr $num % 60`
echo "$day"d,"$hour"h,"$min"m,"$sec"s

Thanks for looking into this and confirming this..

One possible caveat to note is that the order in which these assignments are being made within a single simple command is not defined by the standards as far as I know, so if assignments are interdependent then I think it may be best to use separate simple commands.

For example:

a=1 b=$a

will typically produce a=1 and b=1, but I do not think it is guaranteed by the standards. It might also be a=1 and b="" , which would be the case if it is done right to left or in arbitrary order. Even though I have only come across implementations that go left to right.. ( Simple Commands )

2 Likes

Hi Scrutinizer,
The standards do guarantee it... From The Commands and Utilities Volume of the 2016 edition of the POSIX Standards:

From the beginning ... to the end in shell scripts means left to right. (In some other places in the standard referring to text that could be from a language that is written from right to left, beginning to end means left to right for text that is written from left to right and it means right to left for text that is written from right to left.)

3 Likes