Bash snippets & functions

bash shell

Introduction

Here is the first post of the “Bash snippets & functions” series, which is not that big yet but it will be growing from now on. In this series i will be posting scripts snippets or full sized scripts with the main goal of handling sysadmin / netadmin everyday tasks.

This very first post of the series will be updated very often as it will only contains code snippets & functions and other one-liners.

 

More “bash snippets & functions” posts

 

 

1 Miscellaneous tips & one-liners

  • Count the number of “physical processor(s)
    grep "physical id" /proc/cpuinfo | sort -u | wc -l
    1
  • Count the number of “physical cores per CPU
    grep "cpu cores" /proc/cpuinfo |sort -u |cut -d":" -f2
     2
  • Count the number of “logical cores ” (including multi-threading cores)
    grep -c "processor" /proc/cpuinfo
    2
  • Check the total amount of RAM (in Mo) on your system
    echo $(( $(grep -oE "MemTotal:[[:space:]]+[[:digit:]]+[[:space:]]" /proc/meminfo |awk '{print $2}') / 1000 ))Mo
    4018Mo
  • Make ls to display only filenames (single-column option), and nothing else (in the following command the option is the number “1” not the lower case “L” letter)
    ls -1
  • Create an IP alias from CLI
    /sbin/ifconfig eth0:1 192.168.3.33

    Note : Find more network related examples in “Networking on linux : practical examples

  • Clean bash history (in ~/.bash_history)
    history -c
  • Backup files or directories using “mv” command (from <file> or <dir> to <file>.bak or <dir>.bak)

    mv /path/to/file/or/dir{,.bak}

    Note : This is done using the shell brace expansion. To get better understanding of what this command does replace the mv command by an echo, doing so you will see what the shell is doing…

  • To check and actually “see” what your IFS value is try to use the -vte catcommand options
    [user@testhost ~] $ echo $IFS |cat -vte
    $
    [user@testhost ~] $

 

 

2 Scripts / functions examples

 

2.1 READ with timeout

  • From the ABS site
    #!/bin/bash
    # t-out.sh
    # inspired from "syngin seven" (thanks).
    
    TIMELIMIT=4        # four seconds
    
    read -t $TIMELIMIT variable <&1
    #                           ^^^
    #  "<&1" is for Bash 1.x et 2.x,
    #  but useless for Bash 3.x.
    
    echo
    
    if [ -z "$variable" ]  # is null ?
    then
      echo "Time out, variable not yet initialized"
    else
      echo "variable = $variable"
    fi  
    
    exit 0

 

 

2.2 Fancy “error/warning” messages

  • From linux system functions (/etc/init.d/functionson RHel/Centos)
    # required variables
    BOOTUP=color
    RES_COL=70
    MOVE_TO_COL="echo -en \\033[${RES_COL}G"
    SETCOLOR_SUCCESS="echo -en \\033[1;32m"
    SETCOLOR_FAILURE="echo -en \\033[1;31m"
    SETCOLOR_WARNING="echo -en \\033[1;33m"
    SETCOLOR_NORMAL="echo -en \\033[0;39m"
    
    # function
    echo_failure() {
    [ "$BOOTUP" = "color" ] && $MOVE_TO_COL
    echo -n "["
    [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE
    echo -n $"FAILED"
    [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
    echo -n "]"
    echo -ne "r"
    return 1
    }

 

 

2.3 Get elements (with their offset) from ANY array, using a function

  • From me
    # This function returns every element + their respective offsets
    #+ Usage: Call the function with the array name as "array" (no need to use the full array naming scheme as ${array[@]})
    
    ArrayElemDisplay() {
     n=0                                              # $n initialized to "0" (used in the below while loop)
     array=$1                                         # Array to be processed is given as first parameter
     array_final=( $(eval echo \${${array}[@]}) )     # append the result of the $(eval ...) command to array_final (this way i create a dynamic array name)
    
     while (( n < "${#array_final[@]}" )) ; do        # while loop iterating on each element up to the last one
                                                      #+ (${#array_final[@]} is the offset for the last element)
      for i in "${array_final[@]}" ; do               # for each array element we print its offset and its value
        echo "[$n]: ${i}" ; ((n++))                   #+ and increment the $n var.
      done
    
     done
    }

Note : be aware that the use of “double-quote” in bash array context can be important (see this post for better understanding).

 

 

2.4 The last element of an array

  • From me
    In this example the key command is the second to last one – LastElem=${!#} – it first use the “#” which stores the “total number of arguments” and then using the indirection mark “!” it aims to the argument value itself: the last one.

    # This function returns the last element of the given array,
    #+ Usage: Call the function with the array name as ${array[*]}
    
    GetLastElem() {
     declare -a array
     array=( $@ )        # set the function parameters as the array content
     LastElem=${!#}      # numbers of elements within the array (#) + indirect reference (!) = last element value
     echo ${LastElem}
    }

 

 

2.5 Print the available ANSI control codes and their effects

  • From the wiki.bash-hackers this block of code will print quite a lot of the possible ANSI control code available and their respective effects (all credits goes to constantine)
    for a in 0 1 4 5 7; do
      echo "a=$a "
      for (( f=0; f<=9; f++ )) ; do
        for (( b=0; b<=9; b++ )) ; do
          #echo -ne "f=$f b=$b"
          echo -ne "\\033[${a};3${f};4${b}m"
          echo -ne "\\\\\\\\033[${a};3${f};4${b}m"
          echo -ne "\\033[0m "
        done
      echo
      done
      echo
    done
    echo

 

 

2.6 Append a command stdout to an array

  • Build by me from smart tips from Chris FA Johnson
    • Let’s start with appending the stdout of du -shcommand to an array that will contains all the informations (size + [dir|file]names)
      for i in $(du -s ./*) ; do
        array[${#array[@]}]=${i}
      done

      The smart part of this snippet (which comes from Chris FA Johnson) is the way we append each element found by the loop to the array:

      array[${#array[@]}]=${i} – the inside of the first square brackets is the key (${#array[@]}) this will point to the next available element number (the # is the total number of elements in the array, and as the elements offsets start at 0, it is also equal to the next available element offset!).
      Once we have the”next available element offset” we just have to use it as an offset for the element to be appended by the loop.

      This will create one big array containing all the informations:

      [root@cavepopo pier]# echo ${array[@]}
      144 ./amarok-utils-2.3.0-5.fc13.i686.rpm 24 ./Bureau 41052 ./DATA.tmp.old-server 4 ./Documents 0 ./done 4 ./Images 4 ./Modèles 4 ./Musique 4 ./Public 4 ./REGEX.test 4 ./Téléchargements 4 ./Vidéos
    • Now let’s have it done the good way, by appending to one array or another depending to the type of value (a size or a dir)
      for i in $(du -s ./*); do
        if [[ "${i}" =~ ^[[:digit:]]+$ ]] ; then size_array[${#size_array[@]}]=${i}
        elif [[ "${i}" =~ ^\./.*$ ]] ; then dir_array[${#dir_array[@]}]=${i}
        fi
      done

      This will create two arrays (size_array and dir_array) that respectively contains (in the same order) all the size value in Octets and all the directories names.:

      echo ${size_array[@]}
      144 24 41052 4 0 4 4 4 4 4 4 4
      echo ${dir_array[@]}
      ./amarok-utils-2.3.0-5.fc13.i686.rpm ./Bureau ./DATA.tmp.old-server ./Documents ./done ./Images ./Modèles ./Musique ./Public ./REGEX.test ./Téléchargements ./Vidéos

 

 

2.7 Extract fields from a string

To do this we usually use some pipes combined with grep and cut sometimes even more than this… Here is some simple yet efficient ways to do this task without calling any externals commands but using the internal IFS (Internal Field Separator) (credits goes to Chris FA Johnson)

  1. First method use positional parameters:
    string="these are the fields"  # this is the string out of which we extract the different parts
    set -- ${string} # set command assign each field of the given variable to positional parameters
    Field1=${1}
    Field2=${2}
    Field3=${3}
    Field4=${4}
    # check if everything went smooth:
    echo -e "${Field1}\n${Field2}\n${Field3}\n${Field4}"
    these
    are
    the
    fields # yes it did!
  2. Wait! there is  an even better solution, using a Here Document, see:
    string="these are the fields"
    read Field1 Field2 Field3 Field4 <<EOF # read command takes its input from the heredoc (using <<) NOTE the lack of space
    ${string}
    EOF
    # check if everything went smooth:
    echo -e "${Field1}\n${Field2}\n${Field3}\n${Field4}"
    these
    are
    the
    fields # yes it did!
  3. Now here is my preferred technique, very classy, short, efficient and readable. This is done using a Here String
    string="these are the fields"
    read Field1 Field2 Field3 Field4 <<< "${string}" # read command takes its input from the here string (using <<<) NOTE the one space character
    # check if everything went smooth:
    echo -e "${Field1}\n${Field2}\n${Field3}\n${Field4}"
    these
    are
    the
    fields # yes it did!

Note : In all the previous examples you may need to provide a specific IFS (Internal Field Separator) to get an extraction corresponding to your needs, see the next example for this kind of hack.
DO NOT FORGOT TO SAVE THE DEFAULT VALUE AND RESET TO THIS DEFAULT AFTER YOUR JOB IS DONE

  • Custom IFS use (using the above Here stringexample)
    string="these,are,the,fields"
    OLD_IFS=$IFS
    IFS=","
    read Field1 Field2 Field3 Field4 <<< "${string}" # read command takes its input from the here string (using <<<) NOTE the one space character
    # check if everything went smooth:
    echo -e "${Field1}\n${Field2}\n${Field3}\n${Field4}"
    these
    are
    the
    fields # yes it did!
    # Then reset the IFS to its default value
    IFS=$OLD_IFS

Leave a Reply

Your email address will not be published. Required fields are marked *

This site supports SyntaxHighlighter via WP SyntaxHighlighter. It can highlight your code.
How to highlight your code: Paste your code in the comment form, select it and then click the language link button below. This will wrap your code in a <pre> tag and format it when submitted.