Some tips to speed-up scripts… Add yours, and put the better ones on the top of the page :)
Sed substitution vs Variable substitution
Information
In some cases, both tools can do the same job. As a built-in ash/bash command, variable substitution is faster. Note: this is always true - you can compare each type of variable substitution with an equivalent using an external tool.
Benchmark
$ echo '#!/bin/sh for i in $(seq 1 1000); do echo "slitaz" | sed 's/slitaz/SliTaz/' done' > /tmp/slow $ echo '#!/bin/sh for i in $(seq 1 1000); do A=slitaz echo "${A/slitaz/SliTaz}" done' > /tmp/speed $ chmod +x /tmp/slow /tmp/speed $ time /tmp/slow > real 0m 12.40s $ time /tmp/speed > real 0m 0.04s
Group command vs. Sub-process
Information
Group command “{}” groups several commands into one (as a function). So, output can be grouped too: “{ com1; com2; } | com3”. Sub-process “()” achieves something similar, but creates a shell sub-process; which costs a lot more resources. Another difference is that when you kill an application using CTRL^C, a sub-process is killed instead of a main application - while CTRL^C on grouped commands kills the application itself. Finally, changing directory or variables into sub-processes will not affect the main script which it does with grouped commands. Conclusion: always use group commands instead of sub-processes, and take care ;D
Note: group commands need a newline before closing - or “; }”.
Benchmark
$ echo '#!/bin/sh for i in $(seq 1 10000); do ( echo yo ) done' > /tmp/slow $ echo '#!/bin/sh for i in $(seq 1 10000); do { echo yo; } done' > /tmp/speed $ chmod +x /tmp/slow /tmp/speed $ time /tmp/slow > real 0m 5.36s $ time /tmp/speed > real 0m 0.23s
Grep vs Fgrep
Information
fgrep is exactly the same thing as grep if you don't use patterns (^,$,*,etc.). Fgrep is optimized to handle such cases, particularly when you look for several different plain patterns. A difference can be found even if you look in only one pattern.
Benchmark
$ echo -e "line1\nline2\nline3" > /tmp/file $ echo '#!/bin/sh for i in $(seq 1 1000); do grep 3 /tmp/file done' > /tmp/slow $ echo '#!/bin/sh for i in $(seq 1 1000); do fgrep 3 /tmp/file done' > /tmp/speed $ chmod +x /tmp/slow /tmp/speed $ time /tmp/slow > real 0m 11.87s $ time /tmp/speed > real 0m 3.21s
[ -n "text" ] vs [ "text" ]
Information
The two commands test if “text” exists. Using -n slows the process and weighs down the script a little too.
Benchmark
$ echo '#!/bin/sh for i in $(seq 1 1000000); do [ -n "$i" ] done' > /tmp/slow $ echo '#!/bin/sh for i in $(seq 1 1000000); do [ "$i" ] done' > /tmp/speed $ chmod +x /tmp/slow /tmp/speed $ time /tmp/slow > real 0m 15.56s $ time /tmp/speed > real 0m 14.11s
[ -z "text" ] vs [ ! "text" ] vs ! [ "text" ]
Information
These three commands test if text doesn't exist. [ ! “text” ] and [ -z “text” ] have a similar processing time, while ! [ “text” ] is speedier.
Benchmark
$ echo '#!/bin/sh for i in $(seq 1 1000000); do [ -n "$i" ] done' > /tmp/slow1 $ echo '#!/bin/sh for i in $(seq 1 1000000); do [ -n "$i" ] done' > /tmp/slow2 $ echo '#!/bin/sh for i in $(seq 1 1000000); do [ "$i" ] done' > /tmp/speed $ chmod +x /tmp/slow1 /tmp/slow2 /tmp/speed $ time /tmp/slow1 > real 0m 15.53s $ time /tmp/slow2 > real 0m 15.60s $ time /tmp/speed > real 0m 14.27s
Awk vs Cut
Information
Awk, as cut, can be used to cut a field of a line. Awk can do many other things, while cut is a tool dedicated to this usage; it's why cut is a little faster for this task.
Benchmark
$ echo -e "field1\tfield2\tfield3" > /tmp/file $ echo '#!/bin/sh for i in $(seq 1 5000); do awk '"'"'{ print $2 }'"'"' /tmp/file done' > /tmp/slow $ echo '#!/bin/sh for i in $(seq 5000); do cut -f2 /tmp/file done' > /tmp/speed $ chmod +x /tmp/slow /tmp/speed $ time /tmp/slow > real 0m 16.61s $ time /tmp/speed > real 0m 15.90s
[ condition1 -a condition2 ] vs [ condition1 ] && [ condition2 ]
Information
While && is a fast built-in function, in this case it uses two processes (two test functions) instead of one. So, using -a is a little faster, as the “AND” function itself is slower but makes it possible to use only one process.
Benchmark
$ echo '#!/bin/sh for i in $(seq 1 1000000); do [ "$i" ] && [ "$i" ] done' > /tmp/slow $ echo '#!/bin/sh for i in $(seq 1 1000000); do [ "$i" -a "$i" ] done' > /tmp/speed $ chmod +x /tmp/slow /tmp/speed $ time /tmp/slow > real 0m 23.94s $ time /tmp/speed > real 0m 22.29s