## Shell
### Les bases du shell
## Sommaire
* Les commandes de base
* Les redirections & fichiers spéciaux
* Les commandes (suite)
* Les Expressions régulières (Regex ou regexp)
* Le script Bash
Les commandes de base
## Les basiques des basiques
```bash
mv file1 file2 # Déplacer/renommer un fichier
cp file1 copy1 # Copier un fichier
rm file1 # Supprimer un fichier
rmdir dossier1 # Supprimer un dossier vide
rm -rf dossier1 # Supprimer un dossier et son contenu
mkdir -p dossier/sub1/sub2 # Créer une arborescence de dossier
touch monfichier # Crée un fichier vide
```
## [man](https://man7.org/linux/man-pages/man1/man.1.html)
Doc et référence des commandes systèmes
```bash
man man
```
`Entrée` pour faire défiler, `q` pour quitter
Tips: marche aussi en recherche google
Aussi, souvent il y a un -h ou --help
## [cat](https://man7.org/linux/man-pages/man1/cat.1.html)
Concatène des fichiers vers l'output standard
```bash
cat fichier1 fichier2
```
## [ls](https://man7.org/linux/man-pages/man1/ls.1.html)
Liste le contenu d'un répertoire (le courant par défaut)
```bash
ls .
ls ~
```
## [ls](https://man7.org/linux/man-pages/man1/ls.1.html)
Questions
- Comment lister tous les fichiers d'un dossier en liste, du plus petit au plus gros, avec la taille lisible ?
- Comment lister tous les fichiers d'un dossier en liste, du plus récent au plus vieux, avec la taille lisible ?
## [alias](https://man7.org/linux/man-pages/man1/alias.1p.html)
Créer des alias de commandes (et les lister)
```bash
alias
alias my_ls="ls -larth"
alias remote-ssh="ssh user@xxx.xxx.x.xx"
```
Tips : les alias peuvent être chargés automatiquement en les ajoutant dans `~/.bashrc` ou `~/.bash_aliases` (mieux)
## [alias](https://man7.org/linux/man-pages/man1/alias.1p.html)
Questions
- Que fait la commande `ll` ?
- Créer un alias pour activer le VPN de AB
## [find](https://man7.org/linux/man-pages/man1/find.1.html)
Rechercher des fichiers ou dossiers
```bash
find . -type f # Liste les fichiers
find / -type d # Liste les dossiers
find ~ -name .bashrc # Trouve les fichiers/dossiers nommés .bashrc
find . -type f -mtime -30 -name '*.py' # Liste les fichiers modifiés il y a moins de 30 jours
```
## [grep](https://man7.org/linux/man-pages/man1/grep.1.html)
Recherche un pattern dans des fichiers
```bash
grep error ./logs.txt # Cherche "error" dans le fichiers ./logs.txt
grep -ri error -C5 ./log_folder # ?
```
## [head](https://man7.org/linux/man-pages/man1/head.1.html)
## [tail](https://man7.org/linux/man-pages/man1/tail.1.html)
Affiche les premières/dernières lignes d'un fichier
```bash
head -n 5 ./logs/my_long_log.txt
tail -f ./logs/my_current_file.txt
head -n -5 ./logs/my_long_log.txt # ?
```
Les redirections et fichiers spéciaux
## Entrée, sortie standard et sortie d'erreur
En bash, il existe trois "descripteurs" particuliers
```
stdin => l'entrée (0)
stdout => la sortie standard (1)
stderr => la sortie d'erreur (2)
```
## la redirection de sortie >, >>, >&
Indique au processus de rediriger la sortie standard vers un fichier
```bash
echo "Hello" > message
cat message
echo "Hello2" >> message # ajoute à la fin
cat message
```
## la redirection de sortie >, >>, >&
Il est aussi possible de rediriger une sortie vers un autre descripteur en utilisant `X>&Y`
```bash
echo "Erreur" 1>&2 # "Crée" une erreur
mon_programme 2>&1 >> log.txt # Append tout dans le fichier log.txt
```
## le fichier "trou noir" `/dev/null`
N'affiche rien si on l'affiche, efface tout ce qui est écrit dedans
```bash
echo "Hello" >/dev/null
cat /dev/null
mon_programme >/dev/null 2>&1 # Plus de log
```
Tips: peut servir à faire disparaitre des logs trop verbeux d'une commande (pip par exemple)
## la redirection d'entrée
Il est aussi possible de rediriger l'entrée depuis un fichier
```bash
grep lo < message
```
## le pipe |
Opérateur qui permet d'enchainer des commandes.
Il relie la sortie standard vers l'input de la commande suivante
```bash
ls -a | grep README.md
```
Tips: il existe aussi |& pour la sortie d'erreur
## le pipe |
Question:
- En utilisant `ls`, `tail`, et `wc`, compter le nombre de fichier dans le répertoire courant (. et .. exclus)
- Que fait la commande
```bash
cut -d ' ' -f 1 /var/log/apache2/access_logs | uniq -c | sort -n
```
Tips : https://explainshell.com/ peut aider à comprendre
Les commandes (la suite)
## xargs
Permet de construire et executer des lignes de commandes
```
ls -a | xargs cat
ls -a | grep ".txt$" | xargs -n1 -I {} echo mv {} bazire/{}| sh
```
## awk
Langage de "scanning" et de "processing"
``` bash
cat - > marks.txt << EOF
1) Amit Physics 80
2) Rahul Maths 90
3) Shyam Biology 87
4) Kedar English 85
5) Hari History 89
EOF
awk '{print $3 "\t" $4}' marks.txt
awk '/a/ {print $0}' marks.txt
awk '/a/ {print $4 "\t" $3}' marks.txt
awk '/a/{++cnt} END {print "Count = ", cnt}' marks.txt
awk 'length($0) > 18' marks.txt
```
## sed
Editeur de flux (permet de transformer l'input d'une pipeline de commande entre deux commandes).
"En gros", il permet d'appliquer une regex à un input.
```bash
echo "Bonjour toto" | sed -e "s/toto/$(id -un)/"
echo "help: ## Display commands help" | sed -e 's/^\(.*\):.* ## \(.*\)/\\\\033[36m\1\\\\033[0m \2/g' | xargs echo -e
```
Les expressions régulières
## C'est quoi une Regex ?
Il s'agit d'une syntaxe permettant de reconnaître un ensemble de mots répondant aux contraintes
Cela permet de chercher de manière efficace et de modifier ses expressions
Utilisation : via sed, dans l'éditeur de code, dans les langages
## La grammaire
```
r"abc" => matchera n'importe quelle chaine de caractères contenant abc (dont abc)
r"[a-z]{10}" => matchera n'importe quelle chaine de caractères contenant 10 lettres minuscules
r"[a-zA-Z0-9]{10}" => matchera n'importe quelle chaine de caractères contenant 10 lettres ou chiffres
r"^abc" => matchera n'importe quelle chaine de caractères commençant par 'abc'
r"abc$" => matchera n'importe quelle chaine de caractères terminant par 'abc'
r"^abc$" => matchera exactement 'abc'
r"^.$" => matchera toute chaine de un caractère
r".*" => matchera toutes les chaines, y compris la chaine vide
r".+" => matchera toutes les chaines d'au moins un caractère
```
## La grammaire (suite)
```
() # Groupe capturant
x? # Optionnel
(?=foo) # Lookahead
(?!foo) # Negative Lookahead
```
## Questions
```
r"^[a-c]{1,10}$" => ?
r"^abc?$" => ?
r"^a[bc0-9]*d?$" => ?
```
Tips :
- https://regex101.com/
- https://www.regexplanet.com/advanced/python/index.html
## Exercice
- Copier le premier paragraphe de https://www.lipsum.com/
- Ecrire une régex qui matche tous les mots en majuscules
- Puis, remplacer le mot par la première lettre de ce mot
Script bash
## Le shebang
Donne un lien vers l'interpréteur (quand on lance le fichier en `./monfichier`)
```bash
#!/bin/sh
#!/bin/bash
#!/usr/bin/env python3
```
## Les variables
```bash
#!/bin/bash
# Simple variable
STR="Hello World!"
echo $STR
# Can contain output of commande
OF=/var/my-backup-$(date +%Y%m%d).tgz
echo $OF
# Also, we got list
allThreads=(1 2 4 8 16 32 64 128)
# We can iterate on values
for t in ${allThreads[@]}; do
echo $t
done
# or on index
for i in ${!allThreads[@]}; do
echo $i ${allThreads[$i]}
done
# You can even have mapping (associative array)
declare -A myAssociativeArray
myAssociativeArray[a]=123
myAssociativeArray[b]=456
myAssociativeArray+=([c]=789 [d]=012)
echo ${myAssociativeArray[*]}
for i in ${!myAssociativeArray[@]}; do
echo $i ${myAssociativeArray[$i]}
done
```
## Les arguments
$1, $2, ..., ${10}
Donne un lien vers l'interpréteur (quand on lance le fichier en `./monfichier`)
```bash
#!/bin/bash
echo "Mon script est : $0"
echo "Ou ${BASH_SOURCE[0]}"
echo "Tous mes arguments : $*"
echo "Le nombre d'arguments : $#"
echo "Pour itérer : $@"
echo "Le 1er paramètre est : $1"
echo "Code de retour de la dernière commande : $?"
```
## Exercice
Ecrire un script qui
- prend en entrée un fichier
- vérifie si ce fichier existe
- affiche et retourne une erreur si il n'existe pas
- sinon, compte et affiche le nombre d'occurences de l'argument 2
## Exercice
Ecrire un script qui
- prend en entrée un dossier
- liste et affiche les fichiers CSV
- V1 : pour chaque fichier CSV du dossier, extraire la première colonne et l'exporter dans un fichier suffixé par _col1.csv
- V2 : pour chaque fichier CSV du dossier, extraire les colonnes données en arguments et l'exporter dans un fichier suffixé par _${col}.csv
## Ressources
- [`set -euo pipefail`](https://gist.github.com/vncsna/64825d5609c146e80de8b1fd623011ca)
- https://linuxconfig.org/bash-script-display-usage-and-check-user
- https://www.shellcheck.net/#
- https://regex101.com/
- https://www.regexplanet.com/advanced/python/index.html
- https://explainshell.com
- https://man7.org/linux/man-pages/index.html