return value:

any exit/return/result value other than

0

is considered an error.

you can output the return value of the last command like this:

echo $?
0

inside a script you can exit and return an exit code like this:

exit 123; # will exit program with exit code 123

about [ test ]

[ is a binary program. no joke 😀

the ] closing bracket is signaling [ that the list of arguments is complete

It is said to be equivalent to the test command.

Instead of

if /usr/bin/test -z "$VAR"
then
 echo VAR not set
fi

# You can use:

if /usr/bin/[ -z "$VAR" ]
then
 echo VAR not set
fi

[.man.txt

src: https://superuser.com/questions/334549/what-is-usr-bin-and-how-do-i-use-it

which [
/usr/bin/[
user@Debian8:~$ man [

# but it's not a softlink to test and also not exaclty the same binary as /usr/bin/test
file /usr/bin/[
/usr/bin/[:    ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=c2f4f0658df93da072fa87527ce92c92c1bc1bdd, stripped

file /usr/bin/test
/usr/bin/test: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=477413f30b2afe76b51b5ca9d81bd2f2a641c095, stripped

# possible things you can test for 

# test if file exists (directories under linux are also just special files - hence it returns also true for directories)
if [ -e /path/file ]; then echo "exists"; else echo "does not exist"; fi

# file exists and is readable
if [ -r /path/file ]; then echo "exists"; else echo "does not exist"; fi

# file exists and is writable
if [ -w /path/file ]; then echo "exists"; else echo "does not exist"; fi

# file exists and is runnable
if [ -x /path/file ]; then echo "exists"; else echo "does not exist"; fi
# file exists and is a directory
if [ -d /path/file ]; then echo "exists"; else echo "does not exist"; fi
# file exists and is a block device
if [ -b /path/file ]; then echo "true"; else echo "false"; fi
# file exists and is a char device
if [ -c /path/file ]; then echo "true"; else echo "false"; fi
# file exists and has GUID bit set
if [ -g /path/file ]; then echo "true"; else echo "false"; fi

# file exists and has the sticky bit set
if [ -k /path/file ]; then echo "true"; else echo "false"; fi

# file exists and has the SUID bit set
if [ -u /path/file ]; then echo "true"; else echo "false"; fi
# file exists and is a regular file
if [ -f /path/file ]; then echo "true"; else echo "false"; fi

# file exists and is a symbolic link
if [ -L /path/file ]; then echo "true"; else echo "false"; fi

# tests if file1 newer than file2
if [ file1 -nt file2 ]; then echo "true"; else echo "false"; fi

# tests if file1 older than file2
if [ file1 -ot file2 ]; then echo "true"; else echo "false"; fi

# tests if variable A equals B
if [ $A -eq $B ]; then echo "true"; else echo "false"; fi

# tests if variable A is uniqual to B
if [ $A -ne $B ]; then echo "true"; else echo "false"; fi

# tests if variable A is greater than B (integer expected, will not work with strings or float)
if [ $A -gt $B ]; then echo "true"; else echo "false"; fi

# tests if variable A is greater or equal to B (integer expected, will not work with strings or float)
if [ $A -ge $B ]; then echo "true"; else echo "false"; fi

# tests if variable A is less than B (integer expected, will not work with strings or float)
if [ $A -lt $B ]; then echo "true"; else echo "false"; fi

# tests if variable A is less or equal than B (integer expected, will not work with strings or float)
if [ $A -le $B ]; then echo "true"; else echo "false"; fi

customize $PATH autocomplete

# $PATH is a system variable (environment variable bash settings variable) in which bash searches for executable binaries and scripts.

# change to your home directory

cd

# create new directory

mkdir bin

# add this directory to $PATH

export PATH=$PATH:$HOME/bin; # add custom path to path and make it available to sub-bashs (export (otherwise just valid in current bash)

vim bin/script1.sh; # create a new script, with those lines

#!/bin/bash

echo "Enter your name...."
 read sname

echo "hello $sname";

ESC :x # save and quit in vim

# you could run the script now with

bash bin/script1.sh

# but every script needs the executable right set to function properly

chmod +x bin/script1.sh; # set's execute rights for everybody (owner,group,others)

# now if you type scr... TAB

user@Debian8:~$ scr
 screendump script script1.sh scriptreplay

# bash nicely autocompletes your custom script

if then else

vim bin/script2.sh; # lets make a new script, with those lines

#!/bin/bash
if [[ $1 = "d" ]]
then
    find /etc -maxdepth 1 -type d; # search only for directories under /etc
else
    find /etc -maxdepth 1 -type l; # search only for symbolic links under /etc
fi

ESC :x # save and quit in vim

chmod +x !$; # mark script runnable

# or

chmod +x bin/script2.sh

# !$ is represents the last argument (only the last one - not multiple) used in the last command

loops

# as you might know loops repeat a command a certain amount of times - depending on number of times or other if-conditions

# become root

su

# or

sudo bash

for loop

# this line will add 10 new users with random passwords

for u in $(seq 10) ; do useradd user$u; echo user${u}:Password1 | chpasswd -c SHA512; done

# will remove the 10 just added users again

for u in $(seq 10) ; do userdel -r user$u; done

loop iterate over a list of found files

vi show_all.sh; # create a new file with those lines
#!/bin/bash
# this script will search case-insensitive your whole filesystem for SEARCH_PATTERN
# it will pause when SEARCH_PATTERN was found and output:
#
# file: show path of file
# content: content of file 100 chars before and 100 chars after SEARCH_PATTERN, non-printable chars will be displayed as well by cat -v

SEARCH_PATTERN=$1

echo "...case-insensitive searching for: \"$SEARCH_PATTERN\"";
echo "...please stand by.";

# for z in $(find /) # would be equally correct
for z in `find /`
do
  # test if SEARCH_PATTERN exists in /path/file

  echo "$z";

  if grep -q -i $SEARCH_PATTERN "$z" 2> /dev/null; then

    clear; # grep found something make space on monitor

    echo -e "\n===================================================================="; # visual separator

    echo "file: $z";

    echo -e "\ncontent: ";

    # cat -v "$z" | grep --color=auto -iaPo ".{0,100}$SEARCH_PATTERN.{0,100}"; # will display 100 chars before and after string was found

    cat -v "$z" | grep --color=auto -i $SEARCH_PATTERN; # will only display content of text-files

    echo -e "\n";

    read; # wait for user to hit enter

  fi

done
unset z
exit 0



./show_all.sh torvalds & # search for the kernel-master

while loop

# while being in your home directory

vi bin/script3.sh; # create a new file with those lines

#!/bin/bash

COUNT=10
 while (( COUNT > 0 ))
 do
  echo -e "$COUNT \c"
  sleep 1;
  (( COUNT -- ))
 done

echo -e "\n\nWe have lift off!!"

ESC :x # save and quit vi

# mark the script as runnable

chmod +x !$; # mark script runnable

# or
 chmod +x bin/script3.sh

# and run it - nice countdown

arguments

arguments are the input of a script

vim count_arguments.sh; # create a new file with those lines

#!/bin/bash

echo "the script was started with $0"
echo "you have passed it $# parameters"

./count_arguments.sh
the script was started with ./count_arguments.sh
you have passed it 0 parameters

./count_arguments.sh 1
the script was started with ./count_arguments.sh
you have passed it 1 parameters

./count_arguments.sh 1 2
the script was started with ./count_arguments.sh
you have passed it 2 parameters

./count_arguments.sh 1 2 3
the script was started with ./count_arguments.sh
you have passed it 3 parameters

vim ./add_multiple_arguments.sh; # create a new file with those lines
#!/bin/bash
# pass multiple numbers as arguments that this script will add up

sum=0; # initialize this variable with an value, so one can be sure it is set to that value
while test $# -gt 0
 do
   let sum=sum+$1
   shift
 done
echo the sum of all your input is $sum
unset sum;
exit 0;


./add.sh 1 2 3 4 5 6; # testrun
the sum of all your input is 21

script exit codes error signal handling

scripts not only can output data to screen or files… they also return error-codes to report if everything went as planned or not…

under unix/linux – an error code of zero means „ok“ while anything else might signal an error.

vim mail_test.sh; # create a new file with those lines

#!/bin/bash

DF=$HOME/df.txt

if [ -e $DF ]; # test if file exists
  then
  echo "The file exists!!"
  exit 2; # exit with (error)status of 2 (anything but zero is considered an error result)
fi

df -hT > $DF; # write output of command df to /path/file in $DF variable

mail -s "Disk free $(date +%F)" root < $DF; # mail to root

rm -f $DF; # remove file

ESC :x # save and quit

chmod +x !$; # mark script runnable

# strange enough this does not send a local mail to root but to normal user UID 1000
# this is because of an defined alias in
/etc/aliases

# all mails to root will be forwarded to first standard-user "user" (UID 1000)
cat /etc/aliases |grep root:
root: user

# so if you open up
mail

# you should have mail (try root and non root user)
mail
 Mail version 8.1.2 01/15/2001. Type ? for help.
 "/var/mail/user": 1 message 1 new
 >N 1 user@debian Tue Jun 13 12:12 24/979 Disk free 2017-06-13
 & 1
 Message 1:
 From user@debian Tue Jun 13 12:12:10 2017
 Envelope-to: root@debian
 Delivery-date: Tue, 13 Jun 2017 12:12:10 +0200
 To: root@debian
 Subject: Disk free 2017-06-13
 From: user <user@debian>
 Date: Tue, 13 Jun 2017 12:12:10 +0200

Filesystem Type Size Used Avail Use% Mounted on
 /dev/sda1 ext4 123G 2.7G 115G 3% /
 udev devtmpfs 10M 0 10M 0% /dev
 tmpfs tmpfs 202M 5.0M 197M 3% /run
 tmpfs tmpfs 503M 76K 503M 1% /dev/shm
 tmpfs tmpfs 5.0M 0 5.0M 0% /run/lock
 tmpfs tmpfs 503M 0 503M 0% /sys/fs/cgroup
 /dev/sdc1 ext3 9.8G 3.0G 6.3G 33% /home
 tmpfs tmpfs 101M 12K 101M 1% /run/user/1000

# but the interesting part is the exit code handling

user@Debian8:~$ echo $?; # checkout the error code of the last run script or command
0

# no output = script worked fine = result / exit code = 0 (zero)

this_command_does_not_exist
echo $?; # results into error code 127
-bash: 127: command not found

# any exitcode that is non-zero is regarded as error

touch $HOME/df.txt; # create that file

./mail_test.sh; # then run script again

The file exists!!

# the scrpit now exits with / returns the script-defined error code 2

echo $?
2

Basic Arithmetics

links:

https://bash.cyberciti.biz/guide/Perform_arithmetic_operations

http://www.theunixschool.com/2012/03/typeset-arithmetic-operations.html

http://openbook.rheinwerk-verlag.de/linux/linux_kap11_003.html#dodtp46451953-f764-468e-95fb-d1d06cace77f

vim add.sh; # create a new script, with those lines

#!/bin/bash
# adds two numbers
let summe=$1+$2
echo "the sum of $1 and $2 is $summe"

ESC :x # save and quit in vim

chmod +x add.sh; # mark it runnable

./add.sh 5 12; # test it
the sum of 5 and 12 is 17

typeset -i number
number=301*2; # multiplication
echo $number
602

number=$number+1; # addition
number=$number/3; # division
echo $number
201
number=8\<\<3; # bit shifting
64

# because number was defined as integer (typeset -i) it is not allowed to store strings or float in it
# this is important for clean programming
number=8.3
-bash: 8.3: syntax error: invalid arithmetic operator (error token is ".3")

admin