20 useful Bash scripting tricks

keep-calm-and-bin-bash

We cannot count a Bash as a high-level programming language. Bash scripts don’t perform complicated calculations, hardware access and so on. But we can use it for Linux systems management and orchestration. We’re able to automate routine tasks, wrap CLI applications and just make some fun.

This post about few maneuvers we can use in bash scripting. My thoughts was inspired by “Advanced Bash-Scripting Guide” book. I’d recommend to read this for operations in particular. Doesn’t really matter how can you code on Python or Ruby. Sometimes one shell command in interactive environment is much faster and easier.

1. Semicolon to clean up content in file


There is a difference between fire removal and file purification. Sometimes we need to leave the file like it is, but remove all text from it. For example, when the software service writes log messages and stops to do it if file is disappeared. You can use a dd command like this one…

dd if=/dev/null of=myfile

…but there is also a simple option which you can remember easily.

: > myfile

I have no idea why, but it works!

2. Braces to reduce the command


Sometimes we put the similar arguments in one command. It looks stuffy and leaves the desire to optimize it. For example, this command

mv /usr/share/foo/bar/oldfile /usr/share/foo/bar/newfile

includes /usr/share/foo/bar/ path 2 times. Brace expressions allows to make it shorter like this:

mv /usr/share/foo/bar/{old,new}file

Also it seems such sensible when we need to leave the copy of file before its modification:

cp /etc/apache2/apache2.conf{,.bak}

3. If/else statement reduction


You can accommodate Bash condition statement just in one line. For example, when your new variable depends only on value of old variable:

(( var1 = var0>100?10:20 ))

Also there is a second way of reduction for files operations and any other conditions.

[ ! -f file ] && echo "File not found"

4. Random number generation for a special range


Bash has a builtin random function served as an environmental variable. But it doesn’t support a range of numbers. With while and let statement you can restrict randomization into the special number range.

bottom=1001 #low limit
top=2001 #high limit
while [ "$random_var" -lt "$bottom" ]; do
	random_var=$RANDOM
	let "random_var %= $top"
done

5. Until loop instead of while


Until works when loop condition is not true. Surely you can stop on while loop usage, just changing conditions and condition expressions. But until looks extraordinary and allows to confuse your friends who doesn’t know Bash. Just for fun.

small=10
big=20
until [ $big -lt $small ]
do
 	(( big-- ))
 	(( small++ ))
 	echo "$big $small"
done

6. declare operator to setup read-only variable


Read-only variable makes your code consistent and independent from input data. In some cases you just want to have a persistent object with no possibility to change it. declare operator with -r flag does it well.

var1=5
declare -r var1
echo "var1 value is $var1"
var1=50
echo "var1 is still $var1"

7. TMOUT environmental variable to set the timer


TMOUT variable declaration in your script makes is such useful for input data processing. It saves your code from exceed time-based while loop.

TMOUT=3
echo "You've got $TMOUT seconds to give an answer: "
read answer
if [ -z $answer ]
then echo "Your time is up!"
else echo "Your answer is $answer."
fi

8. bc command for float counting


By default Bash only supports integer number calculations. External bc utility erases this strange lack. Just send to bc your expression through the pipe. Keep an eye on scale parameter – that’s required option to run bc.

echo "scale=10; 10000 * (5 / 100) / 365 * 15" | bc

9. dc command to convert numbers base


dc can calculate operations with float numbers like bc does. But another feature of this – base of numbers conversion. You can pass 4 arguments: aimed number, base, o and p which point the kind of operation.

echo "36 2 o p" | dc

10. Implementation of seq command in for loop


seq command means a sequence of numbers up to the argument has been set. To one-by-one for loop interaction it’s going to be used pretty well. Also you can pass there low limit and sequence interval.

for port in $(seq 1024)
do
	fuser -n tcp $port
done

11. dos2unix to convert line endings in file


Sometimes we’ve got a program and want to run it from the Linux host. It could be the same Bash script which is going to be tested from the shared directory (hello, Vagrant). But we’re getting the message about bad interpreter. The issue is line endings which differs on Windows, Linux and Mac OS. dos2unix and unix2dos utilities provide a simple solution to convert the file format.

dos2unix myfile

12. Colorization of echo output


Bash interpreter support ANSI color scheme. It could be leveraged for text parts selection or just for beautiful script  output. All you need – set the special color codes in echo statement.

echo -e '\E[42;31m'"Red on green"
tput sgr0
echo -e '\E[43;30m'"Black on yellow"
tput sgr0
echo -e '\E[45;34m'"Blue on magenta"
tput sgr0
echo -e '\E[47;36m'"Cyan on white"
tput sgr0

For advanced color sheet look here.

13. Work with array like with stack


Yes, even stack could be implemented in bash. By the indexing tricks you can declare the new array variable at the end and remove this by unset command.

array1[${#array1[*]}]="new"; echo "Length is ${#array1[*]}: array was pushed" #like push
unset array1[${#array1[*]}-1]; echo "Length us ${#array1[*]}: array is poped" #like pop

Queue could be realised too. The enqueue operation will be the same as in stack, the last is a little bit different

unset array1[0];

14. Special characters to change the string case


Do you need an equivalent of upper, lower and title methods? Here we go, take it for granted!

var=veryMixedUpVariable
echo ${var} # veryMixedUpVariable
echo ${var^} # VeryMixedUpVariable
echo ${var^^} # VERYMIXEDUPVARIABLE
echo ${var,} # veryMixedUpVariable
echo ${var,,} # verymixedupvariable

15. “Here documents” for large output


When we set many lines in a single output operation, the first thing ito make this – slash delimiter.

read -p "What's your name: " name
echo "Hello, $name \
	How’re you, $name? \
	Good luck, $name"

But how can you read the code printing out 10 lines that way? But 20? Here document strategy makes your stdout practice the best.

read -p "What's your name: " name
cat <<-ENDOFFILE
	Hello, $name
	How’re you, $name?
	Good luck, $name
ENDOFFILE

You can also set a command output inside of here document.

cat <<OVER
$(	ls -l)
OVER

16. POSIX patterns for the grep command


Grep utility can process POSIX patterns as arguments. Of course, their features is much tighter than regexps. But it reads pretty easy for those who doesn’t know expression means. Sometimes we just need to look for simple patterns in text and that way clarifies what we do.

grep [[:digit:]] ../chapter4/martin_eden #only digits
grep [[:alpha:]] ../chapter4/martin_eden #only alphabet characters
grep [[:blank:]] ../chapter4/martin_eden #only spaces and tabs
grep [[:upper:]] ../chapter4/martin_eden #only uppercase words

17. Subshell use to perform local operations


Bash subshell is a different process. Code of this enclosed inside of parenthesis. The main feature is a data independence from the main script. You can change script variables within the subshell and ensure it won’t be changed in the main script. Practical usage of this feature has many cases.

Also difficult calculations could be sent to the subshell for faster script execution.

myvar=19
echo "Value of variable is $myvar"
( let "myvar+=1"; echo "Value of variable is $myvar" )
echo "Value of variable is $myvar"

18. Indirect reference


With indirect reference you can dynamically generate the variable name. This feature allows to make your scripts more flexible.

myvar="newvar"
newvar="some_value" && echo $newvar
eval ref_var=\$$myvar && echo $ref_var

19. trap command to debug your variable


It is the best debug alternative to myriad of echo statements insertion or bash -x flag. Pretty straightforward to track your data during the program work.

trap 'echo "VARIABLE-TRACE> \$variable = \"$variable\""' DEBUG
variable=5
let 'variable=10'
(( variable++ ))

20. Command prompt emulation through eval


To confuse your co-workers set this script on the shell foreground.

my_prompt="[cazorla19@localhost]$"
while true
do
	echo -n "$my_prompt "
	read my_command
	eval $my_command
done

Do you still think that Bash scripting is restricted and meaningless?

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s