Bash

From Blue-IT.org Wiki

Revision as of 09:53, 17 November 2015 by Apos (talk | contribs) (Kill all processes with a certain name)

Environment

Put this in front of any script to avoid problems when running the script in other languages! The en_US locale should be avaiabel on all systems:

export LC_MESSAGES="en_US.UTF-8"
export LC_TYPE="en_US.UTF-8"
export LANGUAGE="en_US.UTF-8

Terminal or GUI

You can determine, if a script is running in a terminal (TTY) or within a gui:

# check, if we are running in a terminal

if tset -q | grep linux
then
	echo "Running in terminal session ... continue the script "
       GUI=0

else
	# Open a GUI dialog
	if zenity --question --title "GUI Dialog" \
		--text "Would you like to continue?"
       then
            # set some vars
            GUI=1
       else
            exit 1
       fi

fi 


Sending mails

mailx - former known as nail

Tested in

  • Ubuntu 12.04
  • Ubuntu 14.04

Tested with:

  • gmx
  • google

Inspired by

Install packages

sudo apt-get install ca-certificates heirloom-mailx msmtp

Edit configuration files

One for msmtp:

vim ~/.msmtprc
# config options: http://msmtp.sourceforge.net/doc/msmtp.html#A-user-configuration-file
defaults
logfile /tmp/msmtp.log

# settings for gmx
account gmx
auth on
host mail.gmx.de
port 587
user username@gmx.de
from username@gmx.de
password PASSHERE
tls on
tls_trust_file /etc/ssl/certs/ca-certificates.crt

# settings for google
account gmx
auth on
host smtp.gmail.com
port 587
user username@gmail.com
from username@gmail.com
password PASSHERE
tls on
tls_trust_file /etc/ssl/certs/ca-certificates.crt
  
# set default account to
account default: gmx

One for mailx:

vim ~/.mailrc
# set smtp for mailx

# (default)
set from="username@gmx.de"
set sendmail="/usr/bin/msmtp"
set message-sendmail-extra-arguments="-a gmx"

account gmx {
set from="username@gmx.de (Your name) send from command line"
set sendmail="/usr/bin/msmtp"
set message-sendmail-extra-arguments="-a gmx"
}

account google {
set from="username@gmail.com (Your Name) send from command line"
set sendmail="/usr/bin/msmtp"
set message-sendmail-extra-arguments="-a google"
}

Send the mail

mailx -A gmx -s "gmx test" username@gmx.de < /tmp/test_email.txt
echo "mail text" | mailx -A gmx -s "gmx test" username@gmx.de
cat /tmp/test_email.txt | mailx -A gmx -s "gmx test" username@gmx.de

Sending an attachment

echo "mail text" | mailx -A gmx -a attachment.file -s "gmx test" username@gmx.de

Sending dmesg message (or other) via pipe

dmesg | mailx -A gmx -s "$HOSTNAME dmesg" username@gmx.de

Explanation:

-A xxx    : the name of the isp account that must match in ~/.msmtprc AND .mailrc.
            If not specified, the as default defined account will be used.
-s "Text" : the subject
-a Datei  : Attachment

Singleton

The singleton pattern is a very handy one. You can realise it in bash like this:

if ps x | grep -v grep | grep -v $$ | grep $0 | grep -v subl | grep -v vi
then
        echo "$0 already running. Exiting"
        exit 1
else

################################################
# PUT YOUR CODE HERE
# vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv

./run_me

# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
################################################ 
 
fi

Grep

Grep a steam with tail, head

Sometimes you need not to filter a standard out only once, but with tail

tail -f -n 300 /var/log/syslog | stdbuf -o0 grep PATTERN

remove empty lines

cat some_text |  egrep -v '^#|^$'

remove carriage return (newline

echo "something" | tr -d '\n'

Graphical Tools

Sometimes you need to get out of yor script, give a message to your users - visually.

notify-send

See Ubuntu_Desktop#Notify_OSD

#!/bin/bash
 
notify_start() {

    aplay Critical_Error.wav
   
    notify-send   "Backup is is mounted." \
                -i /usr/share/icons/gnome/48x48/actions/document-open-recent.png \
                "Read and write support for you is working."
}

notify_end() {

    notify-send   "Backup Drive is not ready!" \
                -i /usr/share/icons/gnome/48x48/actions/stock-delete.png \
                "Resolve the problem and save your work"
}


while(true); do

	if touch /backup/testfile
	then
		rm /backup/testfile
		notify_start
	else
		notify_end
	fi

sleep 10

done

Monitoring

Sometimes you like to run a monitor in the background. Here an example for checking if a drive had an drive error.

#!/bin/bash

if ps x | grep -v grep | grep -v $$ | grep $0 | grep -v subl | grep -v vi
then
        echo "$0 already running. Exiting"
        exit 1
else

################################################
# PUT YOUR CODE HERE
# vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv

 notify_start() {

     aplay /local/share/sounds/KDE_Critical_Error.wav
    
     notify-send   "Backup is is mounted." \
                 -i /usr/share/icons/gnome/48x48/actions/document-open-recent.png \
                 "Read and write support for you is working."
 }
 
 notify_end() {
 
     aplay	/local/share/sounds/KDE_Critical_Error.wav

     notify-send   "Backup Drive is not ready!" \
                 -i /usr/share/icons/gnome/48x48/actions/stock-delete.png \
                 "Resolve the problem and save your work"
 }

while(true); do

	message_head="SSD WRITE TEST:"
	message_time="date +%F_%Hh:%Ms:%Nms"
	error="ERROR:"
	
	logger "${message_head} $(${message_time}) starting sync"

	if sync
	then
		logger "${message_head} $(${message_time}) sync finished successfully."
	else
		logger "${message_head} $(${message_time}) ${error} while do sync."
	fi

	sleep 2

 	
	if touch ~/testfile
 	then
		logger "${message_head} $(${message_time}) touched testfile in home successfully."

 		if rm ~/testfile 
		then 
			logger "${message_head} $(${message_time}) removed testfile in home successfully."
		else
			logger "${message_head} $(${message_time}) ${error} while removing tesfile in home."
		fi

 	else
		logger "${message_head} $(${message_time}) ${error} while touching tesfile in home."
 		
		notify_end
 	fi
 
sleep 28
 

done

# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
################################################ 
 
fi


sed

Search and replace text in a document with sed

 # Search and replace text in a document globally or first
 # apos@gmx.de - 2008
 #
 # param1: search string
 # param2: replace string
 # param3: the document URL
 search_replace_global(){
 
	search="$(printf "%s\n" "${1}" | sed 's/[][\.*^$/]/\\&/g')"
	replace="$(printf "%s\n" "${2}" | sed 's/[][\.*^$/]/\\&/g')"
	sed -i "s/${search}/${replace}/g" "${3}"
  
 }
   
 search_replace_first(){
   
	search="$(printf "%s\n" "${1}" | sed 's/[][\.*^$/]/\\&/g')"
	replace="$(printf "%s\n" "${2}" | sed 's/[][\.*^$/]/\\&/g')"
	sed -i "s/${search}/${replace}/" "${3}"
  
 }

Cut text out of a file

# Cut text out of a file.
# Searches for the first (!) - and only the first - occurence of the Expression
# "FIRST_TEXT_FRAGMENT" and then, from that line on to the first occurence of 
# "LAST_TEXT_FRAGMENT". It then cuts the lines between these two - 
# including the found lines (!) - out with sed. 
#
# param1: first text fragment
# param2: second text fragment
# param3: input file - the file to inspect
cut_text(){

	THEDOC="${3}"
	#FIRST_TEXT_FRAGMENT="$(printf "%s\n" "${1}" | sed 's/[][\.*^$/]/\\&/g')"
	FIRST_TEXT_FRAGMENT="${1}"
	#LAST_TEXT_FRAGMENT="$(printf "%s\n" "${2}" | sed 's/[][\.*^$/]/\\&/g')"
	LAST_TEXT_FRAGMENT="${2}"

	BEGIN_CUT=$(cat ${THEDOC} | fgrep -n --max-count=1 "${FIRST_TEXT_FRAGMENT}" | cut -d':' -f1)
	BEGIN_CUT=$(expr ${BEGIN_CUT})
	echo ${BEGIN_CUT}

	END_CUT=$(cat ${THEDOC} | sed -e "1,${BEGIN_CUT}d" | fgrep -n --max-count=1 "${LAST_TEXT_FRAGMENT}" | cut -d':' -f1)
	echo ${END_CUT}
	END_CUT=$(expr ${END_CUT} + ${BEGIN_CUT})
	echo ${END_CUT}

	sed -i "${BEGIN_CUT},${END_CUT}d" "${THEDOC}"

}

Renaming files with bad content

find . -depth -name "*.*" -execdir rename 's/:/_/g;s/:/_/g;s/</_/g;s/>/_/g;' "{}" \;

also see

sudo apt-get install detox
detox --help 


Kill all processes with a certain name

vim ~/bin/killall_

#!/bin/bash
PROGRAM="${1}"

if [ ${PROGRAM} = "" ] 
then
	echo "Programname required."
	exit 1
fi

KILL="$(ps x | grep -v grep | grep -v killall | grep -v $(basename $0) | grep "${PROGRAM}" | sed 's/^\ //' | cut -d' ' -f1 | sed 's/ //g')"

if [ "${KILL}" != "" ]
then
	for killme in "${KILL}"
	do
		echo "Killing <9> process number $killme"
		kill -9 $killme
	done
else
	echo "Nothing to kill ..."
fi