Mini-test 1

Redirections
& chainage

Pipes, cut, awk, tee, redirections vers fichiers

9 questions ciblees

| pipe cut / awk > >> 2> 2>&1 tee

Construire des pipelines lisibles

← → naviguer · S solution · M manuel · R recommencer

Question 1 / 9 echauffement : un pipe simple

Echauffement : extraire un nom de fichier de ls

Pour commencer en douceur. ls -1 (chiffre 1, pas la lettre L) liste les fichiers un par ligne. Une ligne = un nom. Mais parfois on veut juste une partie du nom, ou la premiere ligne, ou une colonne de la sortie longue.
$ ls -1 /etc/ adduser.conf alternatives apache2 apparmor.d ...
a) Voir seulement les 5 premieres entrees de /etc/ :
b) Compter combien d'entrees il y a dans /etc/ :
c) Avec ls -l /etc/passwd (mode long), extraire juste le proprietaire (3e colonne) avec cut -d' '. Indice : cut compte chaque espace - utiliser tr -s ' ' pour collapse les espaces multiples en un seul.
d) Beaucoup plus simple : memes infos avec awk (separateur whitespace intelligent) :
CUT(1) - rappel rapide
SYNOPSIS
       cut -d SEPARATEUR -f LISTE     # champs
       cut -c POSITIONS                # caracteres

OPTIONS de -f
       -d C    separateur (UN seul caractere)
       -f N    le Nieme champ
       -f N,M  champs N et M
       -f N-   de N jusqu'a la fin

LIMITE
       cut compte CHAQUE separateur comme un delimiteur. Si la sortie a
       des espaces multiples (ls -l, ps, ...), cut produit des champs vides
       et tout decale. Solutions :
         1) Pre-traiter avec "tr -s ' '" (squeeze : collapse les espaces)
         2) Utiliser awk (whitespace intelligent par defaut)

EXEMPLES
       cut -d':' -f1 /etc/passwd          # noms d'utilisateurs
       cut -c1-10 fichier.txt              # 10 premiers caracteres
       ls -l | tr -s ' ' | cut -d' ' -f3   # proprietaire (apres squeeze)
# a) 5 premieres entrees
ls -1 /etc/ | head -n 5
# Ou simplement
ls /etc/ | head -5

# b) Compter
ls /etc/ | wc -l

# c) Proprietaire avec cut (squeeze d'abord)
ls -l /etc/passwd | tr -s ' ' | cut -d' ' -f3

# d) Beaucoup plus simple avec awk
ls -l /etc/passwd | awk '{print $3}'

Le truc a retenir :

Le reste du mini-test va explorer ces patterns plus en profondeur.

Question 2 / 9 cut/awk sur sortie texte

Extraire la date sans utiliser le format de date

date sans option renvoie un texte du genre : Sat May 17 09:00:00 EDT 2026 (6 champs separes par espaces). L'approche habituelle est date +%Y-%m-%d avec un format. Ici on veut extraire les composantes a la main avec cut ou awk pour pratiquer le chainage.
$ date Sat May 17 09:00:00 EDT 2026 $1 $2 $3 $4 $5 $6
a) Extraire seulement le nom du jour (champ 1, ex: "Sat") avec awk :
b) Extraire seulement l'annee (champ 6) avec awk :
c) Memes choses avec cut -d' ' (utiliser un seul espace comme separateur) :
CUT(1) - rappel
SYNOPSIS
       cut -d SEPARATEUR -f LISTE [FICHIER...]
       cut -c POSITIONS                [FICHIER...]

CHAMPS (-f) - separateur UN seul caractere
       -d' '           espace comme separateur (un seul espace)
       -d':'           deux-points
       -d'\t'          tabulation (defaut si -d absent)

LISTE
       N          le Nieme champ
       N,M        plusieurs champs
       N-M        plage
       N-         de N a la fin

PIEGE classique
       cut compte CHAQUE separateur comme un delimiteur. Pour des espaces
       MULTIPLES (ls -l, ps, etc.), cut produit des champs vides entre les
       espaces. Dans ce cas la, utiliser awk (whitespace intelligent).

EXEMPLES (date)
       date | cut -d' ' -f1          # nom du jour (Sat)
       date | cut -d' ' -f6          # annee (2026)
       date | cut -d' ' -f2,3        # mois + jour ("May 17")
# a) Nom du jour (Sat)
date | awk '{print $1}'

# b) Annee (2026)
date | awk '{print $6}'
# Variante : dernier champ
date | awk '{print $NF}'

# c) Avec cut (le separateur unique fonctionne ici car date utilise UN espace
# entre chaque champ - mais c'est fragile)
date | cut -d' ' -f1        # nom du jour
date | cut -d' ' -f6        # annee

Approche recommandee en production : utiliser date +FORMAT directement, c'est moins fragile :

date '+%a'    # nom du jour abrege (Sat)
date '+%A'    # nom du jour complet (Saturday)
date '+%Y'    # annee 4 chiffres (2026)
date +%Y-%m-%d   # date triable (2026-05-17)

Mais l'approche par cut/awk est utile quand on a une sortie texte deja existante (ex: parsing d'un log, sortie d'une commande tierce). C'est la vraie competence : decouper une ligne en champs.

Pourquoi awk est plus robuste que cut ici : awk gere les espaces multiples (si jamais le format change), cut compte chaque espace.

Question 3 / 9 pipe + extraction de champ

Le pipe et la commande cut

Le fichier /etc/passwd est un tableau a colonnes separees par : : nom:passwd:uid:gid:gecos:home:shell. On veut isoler certaines colonnes.
a) Lister tous les noms d'utilisateurs du systeme (colonne 1) :
b) Lister les shells par defaut de chaque utilisateur (colonne 7) :
c) Lister les shells uniques (chaque shell affiche une seule fois) :
CUT(1) - extrait du manuel
NAME
       cut - extraire des sections (colonnes) de chaque ligne

SYNOPSIS
       cut OPTION... [FICHIER...]

MODES (un seul)
       -f LISTE            par champ (--field), exige -d
       -c LISTE            par position de caractere (--characters)
       -b LISTE            par position d'octet (--bytes)

LISTE (forme commune a -f, -c, -b)
       N          le Nieme
       N-M        plage N a M (inclus)
       N-         de N jusqu'a la fin
       -M         du debut jusqu'a M
       N,M,P      liste de positions

OPTION -f (champs)
       -d SEP             separateur de champs (defaut : TAB)
       --output-delimiter=SEP  separateur de sortie

EXEMPLES
       # 1ere colonne (noms d'utilisateurs)
       cut -d':' -f1 /etc/passwd

       # Colonnes 1 ET 7
       cut -d':' -f1,7 /etc/passwd

       # Premier mot d'une ligne (separateur espace)
       echo "bonjour le monde" | cut -d' ' -f1     # bonjour

       # Premiers 10 caracteres
       cut -c1-10 /etc/passwd

       # De la 5e position jusqu'a la fin
       cut -c5- /etc/passwd

LIMITE de cut
       cut traite UN SEUL caractere comme separateur. Pour des espaces multiples
       (sortie de ls -l, ps, etc.), preferer awk qui split intelligemment.
# a) Noms d'utilisateurs (colonne 1)
cut -d':' -f1 /etc/passwd

# b) Shells par defaut (colonne 7)
cut -d':' -f7 /etc/passwd

# c) Shells uniques (sort puis uniq)
cut -d':' -f7 /etc/passwd | sort | uniq
# Ou plus court avec sort -u :
cut -d':' -f7 /etc/passwd | sort -u

Anatomie d'un pipe : cmd1 | cmd2 envoie la sortie standard de cmd1 vers l'entree standard de cmd2. Empilable a volonte : a | b | c | d.

Piege classique : uniq ne fonctionne que sur des lignes consecutives. Toujours sort | uniq, jamais uniq tout seul.

Question 4 / 9 awk : champs avec espaces multiples

awk : extraire un champ separe par des espaces

La sortie de ls -l a des colonnes separees par plusieurs espaces. Avec cut -d' ' on ne s'en sort pas (cut compte chaque espace comme un separateur). awk fait du whitespace intelligent : tout enchainement d'espaces ou tabulations compte pour un.
$ ls -l /etc/hosts -rw-r--r-- 1 root root 215 May 17 09:00 /etc/hosts ^^^ taille en octets
a) Extraire la taille (5e colonne) de /etc/hosts en utilisant ls -l + awk :
b) Lister juste les noms (derniere colonne) des fichiers de /etc/ en mode long :
AWK(1) - extrait du manuel (usage basique)
NAME
       awk - langage de traitement de texte par lignes / champs

SYNOPSIS
       awk [-F SEP] 'PROGRAMME' [FICHIER...]

PROGRAMME = pattern { action }
       PATTERN  (optionnel) : condition pour declencher l'action
                              ex: /erreur/    (lignes contenant "erreur")
                                   $3 > 100   (3e champ > 100)
                                   NR == 1    (premiere ligne)
       ACTION   : ce qu'on fait quand le pattern matche

       Sans pattern : action appliquee a TOUTES les lignes (cas le plus courant)
       Sans action  : pattern affiche la ligne entiere (defaut : print)

CHAMPS automatiques
       $0          la ligne entiere
       $1          1er champ
       $2          2e champ
       $NF         dernier champ (NF = Number of Fields)
       $(NF-1)     avant-dernier champ

VARIABLES utiles
       NF          nombre de champs sur la ligne courante
       NR          numero de ligne courante (Number of Records)
       FS          separateur d'entree (par defaut : whitespace)
       OFS          separateur de SORTIE (par defaut : un espace)
       FILENAME    nom du fichier en cours

OPTIONS
       -F SEP      separateur (peut etre regex : -F'[:,]' = : OU ,)
       -v VAR=VAL  passer une variable depuis le shell

ACTION print : separer les sorties
       print $1           juste le 1er champ
       print $1, $3       champs 1 et 3 separes par OFS (defaut espace)
       print $0           ligne entiere (equivalent a "print")
       print $1 "-" $2    concatener avec un tiret

EXEMPLES
       # Extraire un champ separe par espaces multiples (la ou cut echoue)
       ls -l | awk '{print $5}'              # tailles
       ls -l | awk '{print $NF}'             # noms (dernier champ)

       # Avec separateur explicite (equivalent a cut)
       awk -F':' '{print $1}' /etc/passwd

       # Filtrer + extraire
       awk -F':' '$7 == "/bin/bash" {print $1}' /etc/passwd
       # Tous les utilisateurs avec /bin/bash comme shell

       # Combiner champs avec separateur custom
       awk -F':' '{print $1 "->" $7}' /etc/passwd

       # Compter (avec NR)
       awk 'END {print NR}' /etc/passwd      # equivaut a wc -l

       # Sommer une colonne
       ls -l | awk '{somme += $5} END {print somme}'   # total octets

       # Numero de ligne + ligne
       awk '{print NR, $0}' fichier.txt
# a) Taille du fichier (5e champ)
ls -l /etc/hosts | awk '{print $5}'

# b) Noms des fichiers (dernier champ)
ls -l /etc/ | awk '{print $NF}'
# Equivalent (le nom est typiquement en colonne 9 dans ls -l)
ls -l /etc/ | awk '{print $9}'

Pourquoi awk plutot que cut ici ?

Astuce du jour : $NF = "dernier champ", sans avoir a compter. Utile quand les colonnes precedentes varient (ex : noms de fichiers avec espaces - mais la attention, awk casse aussi !).

Question 5 / 9 chainage : ps + grep + awk

Isoler le PID d'un processus par nom

Vous voulez le PID du processus sshd pour le passer a une autre commande (kill, strace, lsof -p, etc.). La sortie de ps donne plusieurs colonnes ; il faut isoler la bonne.
$ ps -e | grep sshd 1234 ? 00:00:00 sshd 5678 pts/0 00:00:00 sshd ^^^^ le PID, premiere colonne
a) Chainage ps -e | grep ... | awk pour extraire le PID :
b) Equivalent en une commande (utilitaire dedie) :
c) Tuer tous les processus sshd en une seule commande :
PS(1) - extrait du manuel
NAME
       ps - afficher des informations sur les processus

SYNOPSIS (deux conventions historiques)
       ps -e -f           style System V (avec tirets, options groupees)
       ps aux             style BSD (sans tirets, lettres collees)
       ps -ef et ps aux donnent presque les memes infos

OPTIONS frequentes
       -e                  tous les processus du systeme (System V)
       -f                  format "full" : uid, pid, ppid, c, time, tty, cmd
       a                   tous (BSD, sans le tiret)
       u                   format user-oriented (avec %CPU, %MEM)
       x                   inclure les processus sans terminal (daemons)
       -o FORMAT           format personnalise (cols a la carte)
       -p PID              limiter a un PID
       -U USER             limiter a un utilisateur

COLONNES (selon le format choisi)
       ps -e :     PID TTY  TIME    CMD                          (4 cols, PID en col 1)
       ps aux :    USER PID %CPU %MEM ... CMD                  (PID en col 2)
       ps -ef :    UID PID PPID C STIME TTY TIME CMD            (PID en col 2)

UTILITAIRES DEDIES (souvent plus simples)
       pgrep MOTIF         affiche les PIDs des process dont le nom matche
       pgrep -u USER       limiter a un utilisateur
       pgrep -f MOTIF      matche la ligne de commande complete (pas que le nom)
       pkill MOTIF         tuer par motif (envoyer SIGTERM, ou -SIGNAL)
       pidof PROG          PID du programme par nom exact

EXEMPLES
       # Lister tous les processus
       ps -ef
       ps aux

       # Isoler le PID de sshd par chainage (ATTENTION : selon le format de ps,
       # le PID est dans une colonne differente)
       ps -e | grep sshd | awk '{print $1}'      # avec ps -e (PID en col 1)
       ps aux | grep sshd | awk '{print $2}'     # avec ps aux (PID en col 2)

       # Piege : "grep sshd" matche aussi le grep lui-meme !
       ps aux | grep sshd | grep -v grep | awk '{print $2}'

       # Solution propre : utilitaire dedie
       pgrep sshd                               # equivalent, sans pieges
       pgrep -f sshd

       # Tuer par nom (au lieu de pgrep + kill)
       sudo pkill sshd
PGREP(1) - extrait du manuel
NAME
       pgrep - chercher des processus par nom (et autres criteres)

SYNOPSIS
       pgrep [OPTIONS] MOTIF

DESCRIPTION
       pgrep parcourt les processus en cours et affiche les PIDs dont le
       nom correspond au MOTIF. Remplace le chainage ps | grep | awk,
       sans le piege du grep qui matche lui-meme.

OPTIONS frequentes
       -f                  matcher la ligne de commande complete (pas que le nom)
       -u USER             limiter a un utilisateur
       -x                  match EXACT du nom (pas en sous-chaine)
       -l                  afficher aussi le nom du processus
       -a                  afficher la ligne de commande complete
       -n / -o             garder seulement le plus recent / le plus ancien
       -c                  compter seulement (pas la liste)

EXEMPLES
       # PIDs de tous les sshd
       pgrep sshd

       # PIDs des sshd appartenant a root
       pgrep -u root sshd

       # Avec le nom du processus a cote
       pgrep -l sshd

       # Combiner avec une autre commande
       kill -HUP $(pgrep sshd)
PKILL(1) - extrait du manuel
NAME
       pkill - envoyer un signal a des processus selectionnes par nom

SYNOPSIS
       pkill [-SIGNAL] [OPTIONS] MOTIF

DESCRIPTION
       pkill envoie un signal (par defaut SIGTERM) a chaque processus
       dont le nom correspond au MOTIF. Equivaut a kill $(pgrep MOTIF)
       mais en une seule commande, sans course entre la liste et le kill.

SIGNAUX usuels
       -15 / -TERM          arret propre  (defaut)
       -9  / -KILL          arret force, non rattrapable
       -1  / -HUP           rechargement de config (typique pour daemons)
       -2  / -INT           equivalent Ctrl-C

OPTIONS frequentes
       -f                  matcher la ligne de commande complete
       -u USER             limiter a un utilisateur
       -x                  match EXACT du nom
       -e                  afficher chaque processus tue (PID + nom)
       -c                  afficher seulement le nombre de processus signales

EXEMPLES
       # Tuer tous les sshd (SIGTERM par defaut)
       sudo pkill sshd

       # Recharger la config de tous les nginx
       sudo pkill -HUP nginx

       # Force kill (dernier recours)
       sudo pkill -9 processus-bloque

       # Voir ce qu'on a tue
       sudo pkill -e sshd

ATTENTION
       pkill matche par sous-chaine du nom par defaut. "pkill ssh" tuera
       AUSSI sshd. Utiliser pkill -x pour un match exact.
# a) Chainage classique
ps -e | grep sshd | awk '{print $1}'

# Avec ps aux (PID en colonne 2) - et grep -v grep pour eliminer le grep lui-meme
ps aux | grep sshd | grep -v grep | awk '{print $2}'

# b) Equivalent en une commande
pgrep sshd

# c) Tuer tous les sshd
sudo pkill sshd

Le piege classique : ps aux | grep sshd matche aussi le grep sshd lui-meme. On ajoute | grep -v grep pour l'eliminer. pgrep n'a pas ce probleme.

Anatomie du chainage : ps liste -> grep filtre -> awk extrait la colonne. Chaque etape a un role unique : c'est le principe Unix.

Variantes utiles :

Question 6 / 9 > >> 2> 2>&1

Rediriger stdout et stderr dans des fichiers

Quatre symboles de base pour la redirection vers fichier : >, >>, 2>, 2>&1. Chaque sous-question vise un cas concret.
a) Ecrire le mot bonjour dans /tmp/test.txt en ecrasant le contenu :
b) Ajouter "ligne suivante" a la suite (sans ecraser) :
c) Capturer SEULEMENT les erreurs de find / -name secret dans /tmp/err.log (le reste va comme d'habitude vers la console) :
d) Capturer TOUT (sortie normale + erreurs) de cette commande dans /tmp/all.log, en append :
FIND(1) - extrait du manuel
NAME
       find - chercher des fichiers dans une arborescence

SYNOPSIS
       find [CHEMIN...] [EXPRESSION]

DESCRIPTION
       Parcourt recursivement chaque CHEMIN et applique EXPRESSION a chaque
       fichier rencontre. Par defaut CHEMIN = . (repertoire courant).

CRITERES de recherche
       -name MOTIF         nom de fichier qui matche MOTIF (avec * et ?)
       -iname MOTIF        idem, insensible a la casse
       -type t             type : f fichier, d repertoire, l lien
       -size N             taille : +1M >1Mo, -100k <100ko
       -mtime N            modifie il y a N jours (-7 = moins de 7 jours)
       -user USER          proprietaire
       -perm MODE          permissions (-perm -u+w)
       -maxdepth N         ne pas descendre au-dela de N niveaux

ACTIONS
       -print              afficher le chemin (defaut)
       -delete             EFFACER les fichiers trouves (attention !)
       -exec CMD {} \;     executer CMD pour chaque fichier ({} = chemin)
       -exec CMD {} +      idem, mais regroupe (plus rapide)

PIEGE des permissions
       find / parcourt TOUT, y compris /proc, /root, /etc/ssl/private...
       Sans sudo, plein de "Permission denied" sortent sur stderr.
       D'ou l'utilite de 2> /tmp/err.log (ou 2> /dev/null).

EXEMPLES
       # Tous les fichiers nommes "secret" dans /
       find / -name secret

       # Cacher les erreurs de permission
       find / -name secret 2> /dev/null

       # Capturer les erreurs dans un fichier
       find / -name secret 2> /tmp/err.log

       # Tous les .log de plus de 7 jours dans /var/log
       find /var/log -name '*.log' -mtime +7

       # Effacer les .tmp dans /tmp
       find /tmp -name '*.tmp' -delete

       # Lister tous les repertoires
       find . -type d
BASH(1) - extrait : REDIRECTION
DESCRIPTEURS de fichier
       0     stdin   (entree standard)
       1     stdout  (sortie standard)
       2     stderr  (sortie d'erreur)

SYMBOLES de base
       > FICHIER          stdout vers FICHIER  (ecrase si existe)
       >> FICHIER         stdout vers FICHIER  (append)
       2> FICHIER         stderr vers FICHIER  (ecrase)
       2>> FICHIER        stderr vers FICHIER  (append)
       < FICHIER          lit stdin depuis FICHIER
       2>&1              stderr vers le meme endroit que stdout

SHORTCUTS bash
       &> FICHIER         stdout ET stderr -> FICHIER         (= > F 2>&1)
       &>> FICHIER        idem en append                       (= >> F 2>&1)
       |& cmd             pipe stdout ET stderr               (= 2>&1 | cmd)

L'ORDRE COMPTE
       > fichier 2>&1     OK : stdout va dans fichier, puis stderr suit stdout
       2>&1 > fichier     PIEGE : stderr duplique vers la console, puis stdout
                          redirige - stderr reste sur la console

CAS particuliers
       /dev/null          le trou noir : tout ce qui y va est jete
       > /dev/null        jeter stdout
       > /dev/null 2>&1 tout taire (stdout + stderr)
       >&2                envoyer vers stderr (utile dans un script pour les erreurs)

EXEMPLES
       echo "ligne" > fichier.txt              # ecrase
       echo "ligne" >> fichier.txt             # append
       find / -name x 2> /tmp/err.log         # garder stderr, stdout console
       find / -name x > /tmp/all.log 2>&1     # tout dans all.log
       cmd > /tmp/out.log 2> /tmp/err.log     # SEPARER stdout et stderr
       cmd > /dev/null 2>&1                   # tout taire (silencer total)

       # Dans un script, signaler une erreur sur stderr (bonne pratique) :
       echo "erreur : fichier introuvable" >&2
       exit 1
# a) Ecraser
echo "bonjour" > /tmp/test.txt

# b) Append
echo "ligne suivante" >> /tmp/test.txt

# c) Seulement les erreurs vers fichier (stdout reste sur console)
find / -name secret 2> /tmp/err.log

# d) Tout (stdout + stderr) en append
find / -name secret >> /tmp/all.log 2>&1
# Equivalent (shortcut bash) :
find / -name secret &>> /tmp/all.log

Aide-memoire :

SymboleEffet
> fichierstdout vers fichier, ecrase
>> fichierstdout vers fichier, append
2> fichierstderr vers fichier, ecrase
2>> fichierstderr vers fichier, append
2>&1stderr suit stdout (apres la redirection de stdout)
> F 2>&1tout dans F, ecrase
>> F 2>&1tout dans F, append

Question 7 / 9 tee : voir ET enregistrer

tee : la double sortie

tee ressemble a un T en plomberie : il prend un flux et le duplique vers deux destinations (un fichier ET stdout). Utile pour garder une trace sans perdre l'affichage en direct.
a) Afficher la sortie de ls /etc/ ET la sauver dans /tmp/liste-etc.txt :
b) Ajouter la sortie de date a la fin de /tmp/journal.txt, ET l'afficher :
c) Ecrire "test" dans /etc/conf-protege.txt (necessite sudo) avec tee, en cachant la sortie :
TEE(1) - extrait du manuel
NAME
       tee - lire stdin et l'ecrire dans des fichiers ET stdout

SYNOPSIS
       tee [OPTIONS] [FICHIER...]

OPTIONS
       -a, --append           ajouter aux fichiers au lieu d'ecraser
       -i, --ignore-interrupts  ignorer Ctrl-C (utile dans un long pipe)

POURQUOI tee EST UTILE
       1. Garder une trace SANS perdre l'affichage en temps reel
       2. Ecrire dans un fichier PROTEGE depuis un pipe avec sudo
          (la redirection > est faite par le shell AVANT sudo, donc >
           echoue. tee est une commande, sudo s'applique a tee.)

EXEMPLES
       # Voir ET sauver
       ls /etc/ | tee /tmp/liste-etc.txt

       # Append
       date | tee -a /tmp/journal.txt

       # Sauver dans plusieurs fichiers en meme temps
       echo "secret" | tee /tmp/a.txt /tmp/b.txt /tmp/c.txt

       # Ecrire dans un fichier PROTEGE (le grand classique sudo + redirection)
       # NE MARCHE PAS : sudo echo "x" > /etc/protege
       # (le shell ouvre /etc/protege AVANT sudo, donc > echoue)
       echo "x" | sudo tee /etc/protege

       # Si on veut juste ECRIRE, sans afficher (la sortie pollue le terminal)
       echo "x" | sudo tee /etc/protege > /dev/null

       # Heredoc + tee pour bloc multi-lignes
       sudo tee -a /etc/fail2ban/jail.local > /dev/null <<'EOF'
       [ircd-hybrid]
       enabled = true
       EOF

       # Process substitution : tee vers deux pipes
       cmd | tee >(gzip > out.gz) | wc -l    # compresse + compte en meme temps
# a) Voir ET sauver
ls /etc/ | tee /tmp/liste-etc.txt

# b) Append + afficher
date | tee -a /tmp/journal.txt

# c) Ecrire dans un fichier protege, sans pollution sur la console
echo "test" | sudo tee /etc/conf-protege.txt > /dev/null

L'usage no 1 de tee : ecrire dans un fichier protege depuis un pipe + sudo. La redirection > est faite par le shell avant que sudo entre en jeu, donc sudo echo "x" > /etc/foo echoue. Avec tee, c'est tee qui est lance par sudo, donc tee a les bons droits.

L'usage no 2 : garder un journal pendant un long traitement. Vous voyez la sortie en direct ET vous avez le fichier pour analyse a froid.

Le > /dev/null a la fin : on n'a pas besoin de voir le contenu deux fois (une fois sur la console, une fois ecrit). Le > /dev/null jette la copie qui sort de tee.

Question 8 / 9 parsing de log

Isoler les erreurs d'un fichier de log

Le fichier /var/log/syslog contient des milliers de lignes, dont quelques-unes signalent des erreurs. Vous voulez extraire juste les erreurs et en faire un mini-rapport.
$ tail -5 /var/log/syslog May 17 09:00:01 srv CRON[1234]: (root) CMD (/usr/local/bin/sauvegarde.sh) May 17 09:00:05 srv kernel: usb 1-2: new device May 17 09:01:12 srv sshd[5678]: error: connection from 1.2.3.4 closed May 17 09:02:31 srv kernel: ERROR : disk I/O timeout May 17 09:03:00 srv CRON[9876]: (root) CMD (/usr/local/bin/check.sh)
a) Lister uniquement les lignes contenant error ou ERROR (insensible a la casse) :
b) Compter combien de lignes contiennent l'erreur :
c) Extraire le nom du service (entre le hostname et les [PID]:) des lignes en erreur. Sortie attendue : sshd, kernel... La structure de chaque ligne est DATE HOSTNAME SERVICE[PID]: message. Le service est au 5e champ awk (apres mois/jour/heure/hostname), souvent termine par [pid]: ou :.
d) Top 5 des services qui erreur le plus (services tries par nombre d'erreurs, du plus au moins) :
# a) Lignes en erreur (insensible casse)
grep -i error /var/log/syslog

# b) Compter (-c)
grep -ic error /var/log/syslog

# c) Extraire la colonne 5 (service)
grep -i error /var/log/syslog | awk '{print $5}'

# d) Top 5 services en erreur
grep -i error /var/log/syslog | awk '{print $5}' | sort | uniq -c | sort -rn | head -5

Anatomie du top-N classique :

  1. grep filtre les lignes pertinentes
  2. awk extrait la colonne d'interet
  3. sort rassemble les memes valeurs (prerequis a uniq)
  4. uniq -c regroupe + compte
  5. sort -rn trie par nombre, du plus grand
  6. head -N garde le top N

C'est le pipeline d'analyse le plus utilise en sysadmin.

Variations :

# IPs qui ont fait des tentatives SSH echouees
grep "Failed password" /var/log/auth.log | awk '{print $11}' | sort | uniq -c | sort -rn | head

# Top des URLs visitees (logs Apache/Nginx)
awk '{print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -10

# Comptage par heure (la 3e colonne du syslog est l'heure)
awk '{print $3}' /var/log/syslog | cut -c1-2 | sort | uniq -c

Question 9 / 9 decouper hostnamectl

Decouper la sortie de hostnamectl

hostnamectl affiche plein d'infos systeme. Pour scripter, on veut isoler des valeurs precises (kernel, OS, hostname).
$ hostnamectl Static hostname: irc-prod-01 Icon name: computer-vm Chassis: vm Machine ID: abc123def456... Boot ID: 789ghi012jkl... Operating System: Ubuntu 22.04.3 LTS Kernel: Linux 5.15.0-78-generic Architecture: x86-64
a) Extraire la ligne qui contient le mot Kernel :
b) Extraire juste la valeur du kernel (apres les :, sans les espaces) avec cut :
c) Variante avec awk (en utilisant : comme separateur de champ avec -F) :
d) Le hostname court tout seul (sans les autres infos) :
# a) Lire la ligne Kernel
hostnamectl | grep Kernel

# b) Avec cut (le separateur est ":")
hostnamectl | grep Kernel | cut -d':' -f2

# c) Avec awk
hostnamectl | grep Kernel | awk -F':' '{print $2}'

# d) Le hostname court (l'utilitaire dedie)
hostname
# Ou via hostnamectl :
hostnamectl hostname
# Ou via le chainage classique :
hostnamectl | grep "Static hostname" | cut -d':' -f2 | tr -d ' '

Astuces utiles :

Equivalents directs sans chainage :

ValeurDirectVia hostnamectl
Hostnamehostnamehostnamectl hostname
Kerneluname -rhostnamectl | grep Kernel | cut -d: -f2
OSlsb_release -dshostnamectl | grep "Operating System"
Architectureuname -mhostnamectl | grep Architecture

Bilan

Ce que vous venez de pratiquer

Touche R pour recommencer ce mini-test

« Retour aux mini-tests