BASH – Tips and tricks

Published on Author gryzli

Bash Variable String Manipulation

A = "123456"

# This prints the chars from 3 to 5
# Chars are counting from [0]
echo ${A:3:5}
# prints "456"

echo ${A:1:4}
# prints "2345"

# Prints the number of chars
echo ${#A}
# prints "6"

 

Front Match

These are the examples of a front matching

Front is meant to be “left to right” matching

a = "blog.gryzli.info"

echo ${a#*.}
# prints "gryzli.info"

echo ${a##*.}
# prints "info"

 

Rear Match

These are the examples of a rear matching

Front is meant to be “right to left” matching

a = "blog.gryzli.info"

echo ${a%.*}
# prints "blog.gryzli"

echo ${a%%.*}
# prints "blog"

 

String substitution

 

stringZ=abcABC123ABCabc

echo ${stringZ/abc/xyz} # xyzABC123ABCabc
# Replaces first match of 'abc' with 'xyz'.

echo ${stringZ//abc/xyz} # xyzABC123ABCxyz
# Replaces all matches of 'abc' with # 'xyz'.

 

Remove Suffix From String

string="domain.com"

# Prints "domain" 
echo ${string%.com}

BASH Arrays

 

One-dimensional arrays

  • Define array:
array=(x y z)

 

  • Print element from array:
# Prints "x"
echo ${array[0]}

# Prints "z"
echo ${array[2]}

 

 

  • Print the number of elements in array:
# Prints 3
echo ${#array[*]}

 

 

 

  • Check if array value exists
    # Check if key '4' exists in this array
    key=4
    [ ${array[$key]+abc} ] && echo "Key $key exists"

     

 

Adding value to array without specifying index (array push/unshift)

This could be done by the following syntax:

GRYZ_ARR=()

GRYZ_ARR+=('value1')

GRYZ_ARR+=('value2')

This will add values “value1” and “value2” to the array: GRYZ_ARR

 

Working with associative arrays in BASH

Declare associative array

Here it’s very important to use the “declare -A array_name” notation in order to define working associative array. After the array is defined you can use different methods to fulfill it with elements.

# First declare that this is associative array
declare -A some_array

# Now define array elements 
some_array=(
[key1]=value1
[key2]=value2
[key3]=value3
)

# OR 

some_array[key1]=value1
some_array[key2]=value2

....etc

 

Iterate through associative array

Now that we have our array defined and fulfilled, we can try to iterate through it’s keys and print it’s values.

# Iterate through array: some_array

for key in "${!some_array[@]}";
do 
   # Print the key:value pair
   echo "Key: $key, Value: ${some_array[$key]}"
done

 

 

Bash Arithmetic

If you need to make some arithmetics, here are some tools you could use:

 

Using bc

Basic Calculator (bc) is a mathematical scripting language with a syntax  similiar to C.

If you want to sum floating numbers:

a=0.22;

b=1.11

sum=$(echo "$a + $b" | bc )

# Sum = 1.33

 

Using expr

expr is another basic command which could be used to evaluate basic expressions.

Here are some examples

echo $(expr 5 + 5)   # Result "10"

echo $(expr 5 * 5)   # Result "25"

echo $(expr 5 % 3)   # Result "2" 

 

Using let

 number=5


 let "number--" # $number is 4 

 let "number++" # $number is 5 again

 let  "sum = number + 5" # $sum is 10

 

 

Unsorted tips and tricks

 

find on same filesystem

Find files and directories, without descending from the finding filesystem.

# -xdev disables find of descending to another filesystem
find / -xdev

 

Check if variable is empty

if [ -n $test_var ]; then
echo "$test_var is not empty"
fi

 

Get Symlink destination path

If you want to check the destination of a given symlink, this could be done, by using the command: readlink . The command is part of  the “coreutils” packages, so there is a very big chance, to have it already installed.

# First let's create some symlink
ln -s /root/some_existing_file /root/symlink_to_file

# Now get the destination of the symlink file
readlink /root/symlink_to_file

# Result:
# /root/some_existing_file
# readlink exit code: 0

# If we execute readlink command over NOT SYMLINK file
# then we will get empty result and exit code "1" 

 

Random Sleep

Implementing random sleep from 0 to XXXX seconds

# Sleep some random time from 0 to 5555 seconds 
sleep $[ 1 + $[ RANDOM % 5555 ]]

 

 

Code blocks

{
read row1
read row2
} < /path/to/some/file

 

{
echo 1
echo 2
echo 3 
} > /path/to/file

# cat /path/to/file
# 1\n2\n3\n

Brace expansion

echo \"{These,words,are,quoted}\"   
# "These" "words" "are" "quoted"


cp my_file.{txt,bkp}
# Copies "my_file.txt" to "my_file.bkp"

echo {a..z} # a b c d e f g h i j k l m n o p q r s t u v w x y z
# Echoes characters between a and z.

echo {0..3} # 0 1 2 3
# Echoes characters between 0 and 3.

 Integer expansion

a=3
b=7
echo $[$a+$b]   # 10
echo $[$a*$b]   # 21

test=$(( 1 + 3 ))  # $test is 4

 

Print formated columns output

This will issue printf for every line it gets from the $() command. This way it will print well bounded columns.

! Do not use this for very big files, cause the the “argument” will overflow !

printf "%14s  %14s  %14s  %14s  %14s\n" $(cat some_text_file.txt)

 

BASH Modifying Bash Script During Execution

Recently I found some weird behavior of BASH, which will let you append code to bash script, during it’s execution, and the code will get executed as well.

In order to materialize what I mean, here is the nasty example:

gryzli@localhost [~/temp]$ cat test.sh 
#!/bin/bash 
echo 'echo "THIS WILL BE APPENDED AND EXECUTED"'  >> $0 


gryzli@localhost [~/temp]$ bash test.sh 
THIS WILL BE APPENDED AND EXECUTED

gryzli@localhost [~/temp]$ cat test.sh 
#!/bin/bash 

echo 'echo "THIS WILL BE APPENDED AND EXECUTED"'  >> $0 
echo "THIS WILL BE APPENDED AND EXECUTED"

 

BASH Escaping Quotes

In bash you are able to escape only double-quotes inside double quotes.

Example (This is okay):

gryzli@localhost [~/temp]$ echo "Escaping is \"working\"" 
Escaping is "working"

 

You CAN’T escape single quotes inside single quotes

Example (This is NOT):

# This breaks and shell is waiting for input
gryzli@localhost [~/temp]$ echo 'Escaping is \'NOT\' working '  
> 

 

 

REFERENCES

One of the best places to learn BASH for me is TLDP:

http://tldp.org/LDP/abs/html/abs-guide.html

bugbear