• Uncategorized

About bash : Is-BASH-very-slow

Question Detail

I was solving this question on SPOJ – http://www.spoj.com/problems/ALICESIE/

What the question boils down to print (n+1)/2

This is my C code which passes in 0.03s

    #include <stdio.h>
    int main() {
        int test, n;
        scanf("%d", &test);
        while(test--) {
            scanf("%d", &n);
            printf("%d\n", (n + 1) >> 1);
        }
        return 0;
    }

while this is my BASH code which gives Time Limit Exceeded ( i.e. > 1s )

read test
while (( test-- ))
do
    read n
    echo "$(((n+1)/2))"
done 

Can anyone let me know why is this happening ? Is BASH very slow ?
Thanks.

Question Answer

Bash is slow in executing number-crunching. But that isn’t what Bash was designed for.

Bash is very fast in whipping up a script for automating some repetitive action. It’s fast to modify a faulty Bash script and run it again. It’s fast to find out what exactly a Bash script is doing (as opposed to having to hunt down the source for the C executable you’re looking at).

And the list goes on.

C and Bash are two very different breeds of languages and environments. If you complain about Bash being slow, you are using it for the wrong kind of problem.

“Do not complain that the screwdriver sucks at driving a nail into the wall.”

You’re comparing compiled code with a script language (Bash).

Bash scripts will always be slower than compiled code as they need to be interpreted.

As you probably know, in order to run your code written in C you first need to compile it. When it comes to Bash scripts, you don’t have to read it, the code is just “read on the fly”. So Bash is slower than C.

Bash is slower than C, for sure, because of the reasons given in other answers, but that doesn’t explain what’s happening here. I suspect you’re letting one of your reads hang forever, until timeout. When I implement this:

#!/bin/bash

main() {
    local test
    local i
    local n
    read test
    for (( i=$test; i>0; i--)); do
        read n
        echo "$(((n+1)/2))"
    done
}

time {
    echo 1000
    printf '%d\n' {1002..2}
} | main

It doesn’t take very much time:

real    0m0.033s
user    0m0.029s
sys 0m0.013s

You can force the read statements to time out on their own with the -t flag to read, like this:

main() {
    local test
    local i
    local n
    read -t.3 test
    if [[ -z $test ]]; then
        echo "Failed to read a test value within 300ms."
        return 1
    }
    for (( i=$test; i>0; i--)); do
        read -t.3 n
        if [[ -z $n ]]; then
            echo "Failed to read a value for n within 300ms."
            return 1
        }
        echo "$(((n+1)/2))"
    done
}

The shebang is not added.

#!/bin/bash

read test
while (( test-- ))
do
    read n
    echo "$(((n+1)/2))"
done 

This code I submitted, ran in 0.14 time in SPOJ and was accepted. I don’t see any difference in the question code, except the shebang!!
(For the reader)

You may also like...

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.