beginning

hello world script

#!/bin/bash
echo Hello World
tar -cZf /var/my-backup.tgz /home/me/

If you get something like ./hello.sh: Command not found. Probably the first line '#!/bin/bash' is wrong, issue whereis bash or see 'finding bash' to see how sould you write this line.

#!/bin/bash -x

This will produce some intresting output information

call external programm

PWD=`pwd`
# or
PWD=$(pwd)

Percorsi

Get absolute path to your script

SELF_PATH=$(cd ${0%/*}; pwd)
# imposta il percorso a quello del file corrente e ritorna il percorso corrente
__DIR__=$(cd $(dirname "$0"); pwd)
SCRIPT="`readlink -e $0`"
SCRIPTPATH="`dirname $SCRIPT`"

I/O Redirect: input, output, error

summary:

# Redirect stdout to file
1> filename.txt
 
# Redirect and append stdout to file
1>> filename.txt
 
# Redirect stderr to file
2> filename.txt
 
# Redirect and append stderr to file
2>> filename.txt
 
# Redirect both stdout and stderr to file
&> filename

ouput of a program to be written to a file:

ls -l > ls-l.txt

'ls-l.txt' will be created and it will contain what you would see on the screen if you type the command 'ls -l' and execute it.

This will cause the stderr ouput of a program to be written to a file.

grep da * 2> grep-errors.txt

'grep-errors.txt' will be created and it will contain what you would see the stderr portion of the output of the 'grep da *' command.

stderr ouput of a program to be written to the same filedescriptor than stdout.

grep da * 1>&2

Here, the stdout portion of the command is sent to stderr, you may notice that in differen ways

stderr 2 stdout

This will cause the stderr ouput of a program to be written to the same filedescriptor than stdout.

grep * 2>&1

Here, the stderr portion of the command is sent to stdout, if you pipe to less, you'll see that lines that normally 'dissapear' (as they are written to stderr) are being kept now (because they're on stdout).

stderr and stdout 2 file

This will place every output of a program to a file. This is suitable sometimes for cron entries, if you want a command to pass in absolute silence.

rm -f $(find / -name core) &> /dev/null

Pipes

Pipes let you use (very simple, I insist) the output of a program as the input of another one

This is very simple way to use pipes.

ls -l | sed -e "s/[aeio]/u/g"

Here, the following happens: first the command ls -l is executed, and it's output, instead of being printed, is sent (piped) to the sed program, which in turn, prints what it has to.

Here, the output of the program ls -l is sent to the grep program, which, in turn, will print lines which match the regex "\.txt$".

ls -l | grep "\.txt$"

Variables

You can use variables as in any programming languages. There are no data types. A variable in bash can contain a number, a character, a string of characters.

You have no need to declare a variable, just assigning a value to its reference will create it.

Hello World! using variables

#!/bin/bash
STR="Hello World!"
echo $STR

Then the VALUE of STR variable is retrieved by putting the '$' in at the beginning. Please notice (try it!) that if you don't use the '$' sign, the output of the program will be different, and probably not what you want it to be.

A very simple backup script with variables

#!/bin/bash
OF=/var/my-backup-$(date +%Y%m%d).tgz
tar -cZf $OF /home/me/

Notice the expression '$(date +%Y%m%d)'. If you run the script you'll notice that it runs the command inside the parenthesis, capturing its output.

echo $(ls)

Local variables

Local (non Global) variables can be created by using the keyword local.

#!/bin/bash
HELLO=Hello
function hello {
    local HELLO=World
    echo $HELLO
}
echo $HELLO
hello
echo $HELLO

Conditionals

#!/bin/bash
if [ "foo" = "foo" ]; then
    echo expression evaluated as true
fi
#!/bin/bash
if [ "foo" = "foo" ]; then
   echo expression evaluated as true
else
   echo expression evaluated as false
fi
#!/bin/bash
T1="foo"
T2="bar"
if [ "$T1" = "$T2" ]; then
    echo expression evaluated as true
else
    echo expression evaluated as false
fi

cicli while for

iterare l'output di un comando

#!/bin/bash
for i in $( ls ); do
    echo item: $i
done

one liner:

for FILE in $(ls); do [COMMAND]; done
 
for FILE in $(svn status | grep ? | grep php); do echo $FILE; done

do infinito con intervallo di 5 secondi

while [ 1 ]; do acpi -t; sleep 5; done

iterare una sequenza

#!/bin/bash
for i in `seq 1 10`;
do
    echo $i
done
#!/bin/bash
COUNTER=0
while [  $COUNTER -lt 10 ]; do
    echo The counter is $COUNTER
    let COUNTER=COUNTER+1
done
#!/bin/bash
COUNTER=20
until [  $COUNTER -lt 10 ]; do
    echo COUNTER $COUNTER
    let COUNTER-=1
done
#!/bin/bash
c=1
while [ $c -le 5 ]
do
    echo "Welcone $c times"
    (( c++ ))
done

Functions

Calling a function is just like calling another program, you just write its name.

Notice that a functions don't need to be declared in any specific order. function 'e' prints the first argument it receives. Arguments, within funtions, are treated in the same manner as arguments given to the script.

#!/bin/bash
function quit {
   exit
}
function e {
    echo $1
}
e Hello
e World
quit
echo foo

asking the user

select

#!/bin/bash
OPTIONS="Hello Quit"
select opt in $OPTIONS; do
   if [ "$opt" = "Quit" ]; then
        echo done
        exit
   elif [ "$opt" = "Hello" ]; then
        echo Hello World
   else
        clear
        echo bad option
   fi
done

pass values via CLI. The expression in the first conditional tests if the program has received an argument ($1) and quits if it didn't, showing the user a little usage message.

#!/bin/bash
if [ -z "$1" ]; then
    echo usage: $0 directory
    exit
fi
SRCD=$1
TGTD="/var/backups/"
OF=home-$(date +%Y%m%d).tgz
tar -cZf $TGTD$OF $SRCD

prompt the user for some input, and there are several ways to achive this. This is one of those ways:

#!/bin/bash
echo Please, enter your name
read NAME
echo "Hi $NAME!"

read multiple values

#!/bin/bash
echo Please, enter your firstname and lastname
read FN LN
echo "Hi! $LN, $FN !"

Notifications

notify-send -i /usr/share/pixmaps/FreeMindWindowIcon.xpm "Take a walk"

Arithmetic evaluation

On the command line (or a shell) try this:

echo 1 + 1

If you expected to see '2' you'll be disappointed. What if you want BASH to evaluate some numbers you have? The solution is this:

echo $((1+1))

This will produce a more 'logical' output. This is to evaluate an arithmetic expression. You can achieve this also like this:

echo $[1+1]

If you need to use fractions, or more math or you just want it, you can use bc to evaluate arithmetic expressions.

if i ran "echo $[3/4]" at the command prompt, it would return 0 because bash only uses integers when answering. If you ran "echo 3/4|bc -l", it would properly return 0.75.

the return value of a program

In bash, the return value of a program(0, -1 etc) is stored in a special variable called $?.

    #!/bin/bash
    cd /dada &> /dev/null
    echo rv: $?
    cd $(pwd) &> /dev/null
    echo rv: $?

Capturing a commands output

#!/bin/bash
DBS=`mysql -uroot  -e"show databases"`
for b in $DBS ;
do
    mysql -uroot -e"show tables from $b"
done

Include source files

You can use multiple files with the command source.

You can split up your scripts into files and "include" them with the source aka dot "." operator. The includes do not need to start with "#!/bin/bash", but they must either be in your PATH or have their PATH written exclusively in the main script.

A script that includes another script

#!/bin/bash
source My_Other_Script.sh    # include is in $PATH
source /path/to/the/include/My_Other_Other_Script.sh   # explicit PATH

comparison operators

(1) s1 = s2
(2) s1 != s2
(3) s1 < s2
(4) s1 > s2
(5) -n s1
(6) -z s1
(1) s1 matches s2
(2) s1 does not match s2
(3) __TO-DO__
(4) __TO-DO__
(5) s1 is not null (contains one or more characters)
(6) s1 is null

Comparing two strings:

     #!/bin/bash
    S1='string'
    S2='String'
    if [ $S1=$S2 ];
    then
            echo "S1('$S1') is not equal to S2('$S2')"
    fi
    if [ $S1=$S1 ];
    then
            echo "S1('$S1') is equal to S1('$S1')"
    fi

instead of use if [ $1 = $2 ] as if either $S1 or $S2 is empty, you will get a parse error: "$1"="$2" is better.

Arithmetic operators

-lt (<)
-gt (>)
-le (<=)
-ge (>=)
-eq (==)
-ne (!=)

string functions

string concatenation:

A="X Y"
A+="Z"
echo "$A"
 
foo="Hello"
foo="$foo World"
echo $foo
 
bla=hello
laber=kthx
echo "${bla} ohai ${laber} bye"
printf -v a "%s" "my_var"
foo=$(printf "%s World" "$(date)")

awk template:

var="Hello "
foo=$(awk -v var=$foo 'BEGIN{print var" World"}')

inline commands:

echo "The current time is `date`"
echo "Current User: `echo $USER`"

multiline string:

__TMPL__="hello \
> world"

write/append multiline string to file

#!/bin/bash
myvar="abcef"
cat >/etc/myconfig.conf <<EOL
line 1, ${myvar}
EOL

append:

myvar="abcef"
cat >>/etc/myconfig.conf <<EOL
line 1, ${myvar}
EOL

A simple file renamer

#!/bin/bash
# renames.sh
# basic file renamer
 
criteria=$1
re_match=$2
replace=$3
 
for i in $( ls *$criteria* );
do
    src=$i
    tgt=$(echo $i | sed -e "s/$re_match/$replace/")
    mv $src $tgt
done

Usare Linguaggi di Scripting

#!/usr/bin/env php
<?php
/* your PHP script */
?>

Some bash tricks:

History expansion !! = previous command !$ = last word of previous command !-n = nth previous command !#$ = last word of current line ! will execute the command from history starting with letters after "!"

Brace Expansion: {a..b} = numbers a to b in order. {a,b,c} = words a, b, c. Useful for paths: touch /tmp/{foo,bar,baz}

Parameter Expansion: Suppose that foo=/usr/local/blah.txt ${variable#word} = removes word from the beginning of variable. For example, ${foo#*/} = usr/local/blah.txt ${variableword} = same thing, but removes longest pattern matching word. For example, ${foo*/} = blah.txt ${variable%word} = removes word from end of variable. For example: ${foo%.txt} = /usr/local/blah ${variable%%word} = same thing but longest matching suffix

Process Substitution: <(command) = treats the output of command as a file. diff -u <(ssh web{1,2} cat /etc/passwd)) shows you a unified diff between /etc/passwd on web1 and 2

console percent updater

for( $i=0$i<100$i++ ) {
    
sleep(1);
    echo 
sprintf("\r%3d%% " $i);
}

history, most issued commands

history | awk '{print $2}' | sort | uniq -c | sort -rn | head -20

Useful Commands

Prompt Customization

http://bashish.sourceforge.net/

vi ~/.bashrc
 
echo $PS1
\s-\v\$
\\u@\h \\W]\\$
# minimalist setting:
export PS1="\\t \$"
 
# more info:
export PS1="[\\u@\\H \\W \\@]\\$"
# red color promp
export PS1="\e[0;31m[\u@\h \W]\$ \e[m "
# If id command returns zero, you've root access.
if [ $(id -u) -eq 0 ];
then # you are root, set red colour prompt
  PS1="\\[$(tput setaf 1)\\]\\u@\\h:\\w #\\[$(tput sgr0)\\]"
else # normal
  PS1="[\\u@\\h:\\w] $"
fi

Just assign a new value to PS1:

  • \a : an ASCII bell character (07)
  • \d : the date in "Weekday Month Date" format (e.g., "Tue May 26")
  • \D{format} : the format is passed to strftime(3) and the result is inserted into the prompt string; an empty format results in a locale-specific time representation. The braces are required
  • \e : an ASCII escape character (033)
  • \h : the hostname up to the first '.'
  • \H : the hostname
  • \j : the number of jobs currently managed by the shell
  • \l : the basename of the shell's terminal device name
  • \n : newline
  • \r : carriage return
  • \s : the name of the shell, the basename of $0 (the portion following the final slash)
  • \t : the current time in 24-hour HH:MM:SS format
  • \T : the current time in 12-hour HH:MM:SS format
  • \@ : the current time in 12-hour am/pm format
  • \A : the current time in 24-hour HH:MM format
  • \u : the username of the current user
  • \v : the version of bash (e.g., 2.00)
  • \V : the release of bash, version + patch level (e.g., 2.00.0)
  • \w : the current working directory, with $HOME abbreviated with a tilde
  • \W : the basename of the current working directory, with $HOME abbreviated with a tilde
  • \! : the history number of this command
  • \# : the command number of this command
  • \$ : if the effective UID is 0, a #, otherwise a $
  • \nnn : the character corresponding to the octal number nnn

  • : a backslash
  • \[ : begin a sequence of non-printing characters, which could be used to embed a terminal control sequence into the prompt
  • \] : end a sequence of non-printing characters

using tput program to customize prompt:

export PS1="\[$(tput setaf 1)\]\u@\h:\w $ \[$(tput sgr0)\]"

colored output

 
function cprint() {
    local text="$2"
    local nc='\033[0m'
    case "$1" in
        black  | bk) color="\033[0;30m";;
        red    |  r) color="\033[1;31m";;
        green  |  g) color="\033[1;32m";;
        yellow |  y) color="\033[1;33m";;
        blue   |  b) color="\033[1;34m";;
        purple |  p) color="\033[1;35m";;
        cyan   |  c) color="\033[1;36m";;
        gray   | gr) color="\033[0;37m";;
        #*)
    esac
    printf "${color}${text}${nc}"
}
##]
cprint r  "colorful!\n"
cprint g  "colorful!\n"
cprint y  "colorful!\n"
cprint b  "colorful!\n"
cprint p  "colorful!\n"
cprint c  "colorful!\n"
 
function y_print() { # $1 = string
    TEXT="$1"
    COLOR='\033[1;33m'
    NC='\033[0m'
    printf "${COLOR}${TEXT}${NC}\n"
}
##]
 
y_print "This will be Yellow"