Bash Vs KSH

Bash Vs KSH

Linux and Unix have various shells. Two kinds of these numerous shells are KSH and BASH.

KSH (The Korn Shell) was developed many years before the BASH. Ksh has associative arrays and handles loop syntax better than bash. Also, ksh’s command print is better than bash’s echo command. In other way, ksh does not support history completion, process substitution, and rebindable command-line editing.

Bash has more added extension than ksh. Bash has tab completion and an easier method to set a prompt in order to display the current directory.

Compared to ksh, bash is newer and more popular.

Example of difference ksh and bash in condition test. First bash:

if [ $i -eq 3 ]

and condition test in ksh:

if (($i==3))

Bash can handle exit codes from pipes in a cleaner way. Bash and KSH are both Bourne=compatible shells, they share common functions and features and can be interchangeable to use.

Bash Scripting Best Practices

Bash Scripting Best Practices

Let’s begin with the first line of your script. The first rule always starts script with shebang. Without the shebang line, the system does not know which shell to process. For example:

#!/bin/bash

After shebang line write what is your script about and what it would do.

For debugging printout run your script with the “-x” or “-v” option like:

bash -x script.sh

Use the set lines:

set -e

set -u

set -o pipefail

“-e” to immediately exit if any command has non-zero exit status. “-u” causes the program to exit when you haven’t previously defined variable (except $* and $@). Option “-o pipefail” prevents fails in a pipeline from being masked. The exit status of the last command that threw non-zero exit code is returned.

Never use backticks, use:

$( ... )

Back-ticks are visually similar to single quotes, in a larger script with hundreds of lines you could be confused if it is back-ticks or single quotes.

If you need to create temporary files, use “mktemp” for temporary files and cleanup with “trap”.

Bash Hello World Script

Bash Hello World Script

This bash example creates an archive from /home directory to /backup/ directory as one tar.gz file. Let’s create a file backup.sh. It will consist of two lines:

#!/bin/bash
tar -czf /var/home-backup.tar.gz /home/

First line is a hashpling. Basically, it says who execute script. In this example, we choose /bin/bash.

The second line is tar command. It tarballs and compress the whole directory (/home) to one file.

I recommend you give also the third line (empty line). Why? If you execute this script in unusual UNIXes (ec. SCO UNIX), UNIX coudn’t execute last line, becasuse last symbol of file – EOF (end of file) is different from symbol EOLN (end of line). Symbol EOLN (enter) or semicolon (;) executes command.

Would you to extend this script to some output? Here is an example.

#!/bin/bash
echo -n Creating backup of home directory to /backup...
tar -czf /var/home-backup.tar.gz /home/ >/dev/null 2>&1
echo done.

On the second line, echo with n parameter doesn’t give a new line.

On the third line, output from tar command is redirected to trash (/dev/null).

Last line, just echoes done.

If you don’t know what to put on the first line (hashpling) type:

echo $SHELL

Output: /bin/bash

You will get path to your shell, which can use in the hashspling.

Bash How to Trim String

Bash How to Trim String

You can use a bash parameter expansion, sed, cut, and tr to trim a string.

Let’s use bash parameter expansion to remove all whitespace characters from the variable foo:

foo="Hello world."
echo "${foo//[["space:]]/}"

Output: Helloworld.

“${foo// /}” removes all space characters, “$foo/ /” removes the first space character.

To remove only space characters before and after string use sed:

foo=" Hello world. "
echo "${foo}" | sed -e 's/^[[:space:]]*//'

Output: Hello world.

Easy to use and remember the way how to remove whitespaces before and afterword:

echo " text. text2 " | xargs

xargs remove all whitespaces before “text.” and let one space between text. and text2.

If you want to delete only the last character from the variable:

foo="hello"
echo "${foo::-1}"

Output: hell

Bash How to Echo Array

Bash How to Echo Array

You can define three elements array (there is no space between the name of an array variable, equal symbol, and starting bracket):

FILES=(report.jpg status.txt scan.jpg)

This command will write each element in the array:

echo ${FILES[*]}

Index in shell arrays starts from 0. So, if you want to write just the first element, you can do this command:

echo ${FILES[0]}

Output: report.jpg

Do you want to process each element in the array in the loop? Here is an example:

for ELEMENT in ${FILES[@]}
do
echo File: $ELEMENT.
done

If you want to get only indexes of the array, try this example:

echo ${!FILES[@]}

“${!FILES[@]}” is a relatively new bash feature, it was not included in the original array implementation.

Bash Error Output

Bash Error Output

Bash provides I/O redirection. There are 3 standard files: STDIN (standard input) with descriptor 0, STDOUT (standard output) with descriptor 1, and STDERR (standard error) with descriptor 2.

If you want to redirect your messages to STDERR, you can use >&2 symbol. This symbol is abbreviation of 1>&2 symbol which means, that everything in STDOUT will go to STDERR.

So, if you want to put the message “Cannot delete directory” in STDERR, you can do it this way:

echo Cannot delete directory >&2

Even more, you might to create your own function for error messages:

recho() { echo "$*" >&2 ; }
recho "Cannot delete directory" > /dev/null

Output: Cannot delete the directory

On the first line, we define recho function (error echo). This function will print all its arguments ($*) to STDERR (>&2).

On the second line, we try to use the function. To prove, that output will be written to STDERR, we will redirect STDIN to nowhere (/dev/null). So, if you see some output, it should be in STDERR.

Bash Function How to Return Value

Bash Function How to Return Value

Bash functions have “return” statement, but it only indicates a return status (zero for success and a non-zero value for failure).

function myfunc() {
var='some text'
echo Hello..
return 10
}

myfunc
echo "Return value of previous function is $?"

Output: Hello.. Return value of the previous function is 10

If you want to return value you can use a global variable.

var=0
string () {
var="My return value."
}
string; echo $var

Output: My return value.

It is simple, but using global variables in complex scripts or programs causes harder methods to find and fix bugs.

We can use command substitution and assign an output from function:

string () {
local local_var="Value from function."
echo $local_var
}

var=$( string )
echo $var

Output: Value from function.

It’s good practice to use within-function local variables. Local variables are safer from being changed by another part of the script.

Bash How to Compare Numbers

Bash How to Compare Numbers

The first option is to use the command test to binary compare numbers. For example:

if [ $a -eq $b ]; then
echo "a == b"
else
echo a!=b
fi

An operator”-eq” is equal to, -gt is greater than. For more operators type:

man test

If you are more familiar with symbols “<, >, <=, >=, ==” use double parentheses:

if (( $a < $b )); then
echo "a < b"
fi

For POSIX shells that don’t support double parentheses use test command.

Few examples of test options:

  • -ge: greater or equal
  • -le: less or equal
  • -lt: less than
  • -ne: not equal

Bash How to Return String from Function

Bash How to Return String from Function

You can return string from function in many ways, but you can not use the command “return” to return string:

return "Hello..."

Return statement can return only an integer value.

First option uses a passing argument to the function. To assign to the first argument use in function “$1”:

eval "$1='Hello...'"

Then call the function “my_function”:

my_var=''
my_function my_var
echo $my_var

Output: Hello…

Other way is to use a global variable which you modify within the function.

You can also use command echo to write string value and use command substitution to get it:

hello() {
var='Hello friend.'
echo "$var"
}

greeting=$(hello)
echo $greeting

Bash How to Get Exit Status

Bash How to Get Exit Status

The answer is in this special shell variable “$?”. In this variable is saved exit status of the last command that ended in the background.

In the next example “paranormal_directory” doesn’t exists, at all. It is a paranormal directory 🙂 In this example, $? variable will be 2, because command ls fails:

ls paranormal_directory 1>/dev/null 2>&1
echo $?

Output: 2

Listing the home folder is always safe. Executing ls without any parameter lists home folder of the current user. In this example, ls will succeed, so variable “$?” will be 0:

ls 1>/dev/null 2>&1
echo $?

Output: 0

But be careful, if you read this variable two times (echo $?). In the next example, “echo $?” (on line 3) will show you the output of the first echo command (on line 2):

ls paranormal_directory 1>/dev/null 2>&1
echo $?
echo $?

Output: 2 0

What happens if you don’t specify the exit code in the script? When the exit code is not specified with the exit command, the exit code of the script will be the exit code of the last executed command.

Bash How to Run Command from Variable

Bash How to Run Command from Variable

You can run the command from variable using the command “eval”:

eval $foo

The command eval takes an argument, construct and execute the command of it.

Another option is the symbol “$”:

$foo

Let’s have the following example:

foo='date'
foo2='echo "Hello :)"'
eval $foo
$foo2

Output: Wed Jul 27 14:17:40 CEST 2016 Hello 🙂

It is also possible to use bash’s option -c which executes commands from variables in a separate script, that inherits file descriptors, environment variables.

bash -c "$foo"

eval “$foo” executes the command in the current script, not in a separate script. If you want to execute the eval command in a separate script, use brackets: (eval “$1”).