What is a shell? In any Linux system, a shell is an interface to process user input by executing the relevant commands and displaying the output to the user. In simple terms, a shell is an environment to perform tasks via the command-line interface. There are mainly two types of shells in Linux: the Bourne shell and the C shell. The Bourne shell has many subcategories:
- POSIX shell (sh)
- Bourne shell (sh)
- Korn shell (ksh)
- Bourne Again shell (bash)
- Z shell (zsh)
- Debian Almquist shell (dash)
In this article, let’s dive into two particular shells: Bash and Dash.
2. Key Differences Between Dash and Bash
Bash has been the default standard interactive shell in most Linux distributions for a long time. However, from Ubuntu 6.10 onwards, Dash replaced Bash. Efficiency was the main reason to change the default shell.
Bash is a full-featured shell for interactive use and is still the default login shell. However, it is much larger and slower to launch and use. On the other hand, the Dash shell is a simplistic modern POSIX-compliant version of the Bourne shell. Dash has several feature advantages:
- Consumes minimal disk space, yet it’s feature-rich
- Low dependence on shared libraries
- Relatively low boot time
- Better execution speed
Though the Bash shell is more versatile, extensive, and preferred for user-interactive sessions, the mentioned features of Dash outweigh Bash in terms of speed. In the following sections, let’s compare the performance of both shells.
3. Start-up Time Benchmark Testing
Simple benchmark tests consist of executing a set of commands for a fixed iteration and calculating the time consumption for the whole process. Both shells of interest will undergo the same testing with time consumption measuring their relative performance.
The start-up time benchmark is a simple test with the “no-operation” (no-op, :) command. We start the shell in each iteration and do nothing with no-op. The total time consumed will indicate the start-up time for each shell as there are no extra operations performed.
Firstly, let’s see the start-up time test for Bash:
$ cat bash_benchmark_script #!/bin/bash for i in $(seq 1 1000); do bash -c ":" ; done $ time bash bash_benchmark_script real 0m1.486s user 0m1.152s sys 0m0.327s
Here we have used the time utility to find out the time taken to execute the given script. The bash_benchmark_script tries to invoke the Bash shell to run no-op for 1000 iterations. This means that it takes 1.48sec just to start up the Bash shell 1000 times.
Secondly, let’s check the start-up time test for Dash:
$ cat dash_benchmark_script #!/bin/dash for i in $(seq 1 1000); do dash -c ":" ; done $ time dash dash_benchmark_script real 0m0.999s user 0m0.819s sys 0m0.134s
The dash_benchmark_script tries to invoke the Dash shell to do no-op for 1000 iterations. This means that it takes just 0.9sec to start up the Dash shell 1000 times.
In short, we see that the start-up time of the Dash shell is about a third less than that of the Bash shell. This efficiency is due to the lower dependency on the shared libraries and smaller total size of Dash in comparison with Bash.
Now that we compared the start-up timing, let’s dive deep into real-time compute performance comparison in the following section.
4. The Shellbench Testing
Shellbench is a benchmark utility for POSIX shell comparison. The shellbench utility runs any given set of commands in an infinite loop for about a second. Then, it returns the number of executions per second, using which the relative performance of the scripting shell is calculated. Consequently, a higher number of executions per second implies better performance.
Furthermore, the utility provides eight sample benchmark tests to check performance with different operations. Actually, we can run tests on several shells like sh, bash, ksh, zsh, and dash at the same time to compare performance.
Now, let’s use the shellbench utility to compare the performance between Bash and Dash:
$ ./shellbench -s bash,dash sample/* ---------------------------------------------------- name bash dash ---------------------------------------------------- assign.sh: positional params 354,961 1,552,364 assign.sh: variable 486,657 1,826,733 assign.sh: local var 505,224 1,888,458 cmp.sh: [ ] 254,506 903,775 cmp.sh: case 487,977 1,984,710 count.sh: posix 394,556 1,219,866 eval.sh: direct assign 265,855 1,219,592 eval.sh: eval assign 127,999 780,953 eval.sh: command subs 2,171 4,932 func.sh: no func 471,705 1,964,937 func.sh: func 273,133 1,563,748 null.sh: assign variable 545,798 1,858,063 null.sh: define function 591,780 2,189,993 null.sh: undefined variable 440,758 1,943,129 null.sh: : command 501,115 1,946,933 output.sh: echo 331,422 1,020,727 output.sh: printf 318,519 999,600 subshell.sh: no subshell 488,495 1,966,461 subshell.sh: brace 454,453 1,920,703 subshell.sh: subshell 2,586 5,206 subshell.sh: command subs 2,234 4,963 subshell.sh: external command 1,037 1,083 ---------------------------------------------------- * count: number of executions per second
Note that we specified the shells of interest (bash,dash) via the -s switch. The main argument to shellbench consists of scripts to run for benchmarking. Here, we used the sample scripts that come with Shellbench itself.
In addition, we can see a graphical representation of the results:
The bar graph shows the better performance of Dash in comparison with Bash over multiple operations like variable assignment, logical comparison, counting operation, expression evaluation, function call, display operation, and sub-shell operations. The Dash shell is roughly 2-5 times more efficient than the Bash shell in terms of execution speed.
Thus from the above experiments, we conclude that the Dash shell, although with a smaller feature set, is much more efficient than the Bash shell in terms of both start-up time and execution speed.