Table des matières

Initiation aux commandes Bash


Bash acronyme de Bourne Again Shell est un interpréteur de commandes développé en 1989 par Brian Fox. Au début de sa création, ce petit logiciel permettait de rendre exécutable les programes GNU installé sur un système. Aujourd'hui il comporte de nombreuses extensions et il existe des alternatives comme CSH, KSH, ZSH, ou même Oh My ZSH.

Guide avancé :

Voir les directives chargé par le terminal :

stty -a
env

Utilisation des variables

v="pain"
# Variable statique:
readonly p=22
f=20
echo "Du ${var} à ${p}0,$(($p-$f))0 euros!"
$ Du pain à 220,20 euros!

https://tldp.org/LDP/abs/html/parameter-substitution.html

var="${1:-default}"
echo "var = $var"
$ ./script.sh param1
$ var = param1
$ ./script.sh
$ var = default
string="chaine"
echo ${#string}

Concaténation

a="a"
b="b"
x="${a} ${b}"
echo ${x}
$ a b

Utiliser des variables d'environnements et arguments

Executer une commande externe

cmd=$(pwd)
echo $cmd
$ /home/utilisateur

Transformer une chaîne en tableau

LISTE_FERIER_FR=(
"Lundi de Pâques"
"Jour de l'Armistice"
)
 
Si_ferier() {
 
for i in "${!LISTE_FERIER_FR[@]}" ; do  
 
  gcal --cc-holidays=fr --holiday-list=long |grep "${LISTE_FERIER[$i]}" >/dev/null
  if [[ $? ]]
  then
    return 0
  fi  
 
done
 
}
validate_phpversion() {
    php_version="$1"
    if [[ ! " ${PHP_VERSIONS[*]} " =~ ${php_version} ]]; then
        echo "Wrong PHP version!"
        return 1
    fi
}
var="a b c d"
var=($var)
echo "Nombre de cases : ${#list[@]}"
Nombre de cases : 4
shift 1
for domain in "$@"; do
    domains="${domains:+${domains} }${domain}"
done
declare -A DATES
 
for i in 1 2 3 4; do
  DATES[$i]=$( date +"%Y%m%d" --date="$i days ago" )
done
 
for i in "${DATES[@]}" ; do echo "$i"; done

Découpage d'une chaine

Ressource : https://tldp.org/LDP/abs/html/string-manipulation.html

⇒ Supprime ce qui est avant le dernier terme rencontré :

var="test.tst.ts.t"
echo ${var##*.}
$ t

⇒ Supprime ce qui est avant le premier therme rencontré :

var="test.tst.ts.t"
echo ${var#*.}
$ tst.ts.t

⇒ Supprime ce qui est après le dernier therme rencontré :

var="test.tst.ts.t"
echo ${var%.*}
$ test.tst.ts

⇒ Supprime ce qui est après le premier therme rencontré :

var="test.tst.ts.t"
echo ${var%%.*}
$ test

⇒ Sélectionner une portion d'une chaine !

var="test.tst.ts.t"
echo ${var:5:3}"
$ tst

Substituer (trouver et remplacer) un mot

var="bonjour le monde!"
echo ${var/bonjour/aurevoir}
$ aurevoir le monde!

Les conditions

En pratique c'est la commande test qui sera appelé lorsque l'on utilise ces caractères “[” et “]”

x=true
if [ $x ] || [ "$x" = "var_inutile" ]; then
        echo true
elif [ "$x" = "autre" ]; then
        echo false
else
        echo "else"
fi
 
if ss -tr |grep microsoft-ds 1>/dev/null ; then
  echo utilisateur connecté
else
  echo utilisateur deconnecté
fi

Sur une seule ligne :

x=true
[ $x ]; echo $?;

Si 0 = vrai. Si 1 = faux (celà signifie généralement qu'il y a une erreur).

a=true
b=false
[ $a -a $b ]; echo $?;
$ 0
a=true
b=false
[ $a -o $b ]; echo $?;
$ 0
Lors d'une comparaison avec une chaine renseigné dans une variable, il faut faire “$chaine”.

Cas réel (en mode sale sans unité systemd utilisateur):

echo Check si planka est lancé...

pstree -u $USER |grep node >/dev/null
planka_started=$?

[ ${planka_started} -ne 0 ] && {
  cd ~/planka
  REACT_APP_SERVER_BASE_URL=https://todo.autarcie.org NODE_ENV=production node app.js --prod &
}

Opérateurs de comparaisons

un man test permet de voir la liste des comparaison supporté

Opération sur les chaines

Opérateur de comparaison numérique

Les boucles

La boucle “for” est rudimentaire. C'est à dire qu'il faut obligatoirement un tableau pour qu'elles puissent fonctionner.

⇒ For :

# Lis un tableau :
 
a=(un deux trois quatre)
b=5
 
for x in ${a[@]}
do
        echo x= $x
done
 
# Simple boucle avec un timer :
 
for sec in $(req 1 5) ; do
  echo $sec
  sleep 1
done

⇒ while :

while [ ! -f "fichier.txt" ]
do
	sleep 1;
done
echo fichier trouvé!

ou ainsi

cat plusieurs-lignes.txt | while red mot ; do echo $mot ; done

Structures de contrôles

case $1 in
        start)
                echo start! ;;
        stop|restart)
                echo stop ou restart! ;;
        *)
                echo autre.. ?
esac
while :; do
    case ${1:-''} in
        -h|-\?|--help)
            show_help
            exit 0
            ;;
        -V|--version)
            show_version
            exit 0
            ;;
        *)
            # Default case: If no more options then break out of the loop.
            break
            ;;
    esac
    shift
done

Les fonctions

fonc() {
	echo mon parametre : $1
}
 
fonc coucou
$ mon parametre : coucou

Les codes couleurs

echo -e "\033[31m ROUGE \033[0m"

Regex

chaine="bruno est present"
 
if [[ "$chaine" =~ "present" ]]
then
    echo "le mot est bien présent dans la chaine!
fi

Inclure un tableau dans un fichier

Admettons que nous avons ce fichier :

boot.html
#__SCANS_ITEMS__/

Et que nous avons ce script :

items=$(ls -1)
items=($items)
awk -v r="$items" '{gsub(/#__SCANS_ITEMS__/,r)}1' boot.html > boot.html.tmp
mv boot.html.tmp boot.html

En l'exécutant, il va substituer les valeurs inclus dans items par la ligne indiqué. Ici #SCANS_ITEMS/.

Variables d'environnement Bash

On peut les lister avec la commande suivante :

set

Ou ajouter des options pour modifier le comportement de bash

e

Quelques commandes supplémentaires

cat > /tmp/exemple.txt <<EOF
Le contenu de ce fichier
est sur plusieurs lignes.
:)
EOF
read -p "Entrez votre mot de passe : " -s pass
script.sh
#!/bin/bash
cat /dev/stdin |grep maison
$ cat nombreuses-lignes.txt |script.sh
maison
maisonnette

Plus d'infos à ce sujet : http://lipn.univ-paris13.fr/~cerin/SE/S2SE_01_LectureFichiersShell2.html

sleep 20 &

Celui-ci peut être mis en pause avec les touches : Ctrl+z

cat /etc/passwd | wc -l
wc -l /etc/passwd
uniq <fichier> -u
sed 's|# \(.*blue.*\)|\1|' input.txt
sed -i "307s/.*/\tdisableThirdPartyRequests: true,/" input.txt
zgrep repaired /var/log/mysql/error.log* |sed "s/.*Table '.\(.*\)'.*/\1/" |sort|uniq
grep -e 'postgres' /etc/postgres       # Retournera que la ligne contenant postgres
grep -v 'postgres' /etc/postgres       # Retournera tout sauf la ligne contenant postgres
cat /etc/passwd | head -n 20 | tail -n 5
awk -F ":" '{ print $1 $NF }' /etc/passwd
awk 'BEGIN { FS = ":"
             printf ("\nUser id\t\tShell\n\n") }
           { printf ("%s\t\t%s\n", $1, $7) }
     END   { printf "\nTotal numer of user ids = %d\n", NR } ' /etc/passwd
awk 'END { print "Total ligne : " NR }' /etc/passwd
awk ' BEGIN { FS = ","  }
      { 
         if ( NR == 1 || NR == 4 || NR == 5 )
              printf ("%s,%s,%s,%s\n", $1, $2, $3, $4) 
         else {
               sum2 += $2
               sum3 += $3
               sum4 += $4
               printf ("%s,%6d,%6d,%6d\n", $1, $2, $3, $4) }
      }
      END    { printf ("Totals,%6d,%6d,%6d\n", sum2, sum3, sum4) } 
' <<EOF
Expenditure,2012,2013,2014
Advertising,200015,233912,189928
Bank charges, 23029, 26667, 34990
***********,****,****,****
Expenditure,2015,2016,2017
Bank charges, 23029, 26667, 34990
Boarding and Lodging,237899,453326,356625
EOF
echo "debut"
 
cat <<EOF >log.txt 
        Status of backup as on $(date)
        Where ?? -> $HOME
EOF
 
echo "fin"

* Jouer avec les couleurs

https://misc.flogisoft.com/bash/tip_colors_and_formatting

exec <&-
mail -s 'test sujet' -a From:contact@domaine.com user@domaine.fr <<< 'test'