Qu'est ce que le shell sous GNU/Linux ?
Le shell est à Linux ce que MS-DOS est à Windows.
En effet, sur un système GNU/Linux, il est très important de connaitre les bases du shell.
Même si les interfaces graphique sont là pour simplifier les opérations, il est parfois nécessaire, voir indispensable, de savoir utiliser des commandes GNU/Linux.
Parfois, il n'y a pas toujours de programmes avec de belles interfaces graphiques pour faire ce que nous souhaitons.
Parfois, il est plus simple et plus rapide de faire telle ou telle action via les lignes de commandes.
Rechercher des fichiers, créer des répertoires, rechercher du texte dans plusieurs fichiers, renommer en masse tout un ensemble de fichier selon certains critères, se déplacer au sein de l'arborescence GNU/Linux etc etc ...
Et enfin, le plus important, écrire ses propres scripts afin d'automatiser certaines actions répétitives.
Extraits du livre "Programmation Shell sous Unix / Linux" aux éditions ENI que je conseil très fortement de se procurer.
Une commande externe est un fichier présent dans l'arborescence.
Quand un utilisateur exécute la commande ls, le shell demande au noyau Linux d'exécuter le fichier /bin/ls
Sont considérés comme commandes externes, tous les fichiers au format binaire exécutable ainsi que tous les fichiers au format texte représentant un script de commandes.
La commande file indique le type de données contenues dans un fichier.
$ file /bin/ls
/bin/ls: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, stripped
$ file monscript
monscript: POSIX shell script text executable
L'argument de la commande file est un nom de fichier indiqué en relatif ou en absolu
Une commande interne est intégrée au processus shell.
Elle n'a aucune correspondance avec un fichier sur le disque.
La commande type indique si une commande est interne ou externe.
$ type cd
cd est une primitive du shell
$ type ls
ls est un alias vers « ls --color=auto »
La commande type prend en argument le nom d'une commande. Si cette dernière n'est pas une commande interne, elle est recherchée dans les répertoires indiqués dans la variable PATH
Certaines commandes ont une implémentation interne et externe.
La commande pwd est une commande interne :
$ type pwd
pwd est une primitive du shell
La commande pwd possède également une implémentation externe :
$ ls -l /bin/pwd
-rwxr-xr-x 1 root root 34376 2010-09-21 20:33 /bin/pwd
Pour forcer l'utilisation de la commande externe, il faut indiquer l'emplacement de la commande :
$ /bin/pwd
/home
$ cd /bin
$ ./pwd
/bin
La commande interne echo permet d'afficher des données à l'écran.
$ echo Ceci est un exemple
Ceci est un exemple
Il faut échapper l'apostrophe avec l'antislash
$ echo Un exemple avec l\'apostrophe
Un exemple avec l'apostrophe
Il faut échapper les guillemets avec l'antislash
$ echo Un exemple avec des \"guillemets\"
Un exemple avec des "guillemets"
En bash, il faut obligatoirement utilisé l'option "-e" pour utiliser les caractères spéciaux suivants.
$ echo -e "Un exemple\navec un saut de ligne"
Un exemple
avec un saut de ligne
Sans le caractère "\c"
$ echo -e "Une ligne" ; echo -e "Une autre ligne"
Une ligne
Une autre ligne
Avec le caractère "\c"
$ echo -e "Une ligne\c" ; echo -e "Une autre ligne"
Une ligneUne autre ligne
L'option -n remplace le caractère "\c"
$ echo -n "Une ligne" ; echo "Une autre ligne"
Une ligneUne autre ligne
$ echo -e "Voici 1 tabulation\tet la suite"
Voici 1 tabulation et la suite
$ echo -e "Afficher un antislash\\"
Afficher un antislash\
Liste des caractères spéciaux :
\0NNN | Valeur d'un caractère exprimé en octal |
\\ | Antislash |
\a | Bip |
\b | Effacement du caractère précédent |
\c | Suppression du saut de ligne en fin de ligne |
\f | Saut de page |
\n | Saut de ligne |
\r | Retour chariot |
\t | Tabulation horizontale |
\v | Tabulation verticale |
Le caractère "~" représente le répertoire HOME de l'utilisateur.
Par exemple, pour l'utilisateur "toto"
$ cd ~
$ pwd
/home/toto
Copier le fichier "fichier1" du répertoire /tmp dans le répertoire /home/toto
$ cd /tmp
$ cp fichier1 ~
Copier le fichier "fichier2" du répertoire /tmp dans le répertoire /home/toto/mesfichiers
$ cd /tmp
$ cp fichier2 ~/mesfichiers
Si le caractère "~" est immédiatement suivi d'un mot, ce dernier est considéré comme un nom d'utilisateur.
Copier le fichier "fichier3" du répertoire /home/toto vers le répertoire /home/titi
$ cd ~
$ pwd
/home/toto
$ cp fichier3 ~titi
Copier le fichier "fichier4" du répertoire /home/toto vers le répertoire /home/titi/tmp
$ cd ~
$ pwd
/home/toto
$ cp fichier4 ~titi/tmp
La commande cd, sans arguments, permet à l'utilisateur de se placer dans son répertoire HOME.
$ pwd
/tmp
$ cd
$ pwd
/home/toto
Identique en utilisant le caractère "~"
$ cd ~
Pour se rendre dans le répertoire HOME de tata :
$ pwd
/home/toto
$ cd ~tata
$ pwd
/home/tata
Pour revenir au répertoire précédent avec la commande "cd -" :
$ cd -
$ pwd
/home/toto
Attention, certaines de ces expressions ne fonctionnent pas toutes avec les mêmes shell.
Pour certaines, elles sont compatibles BASH, pour d'autres ZSH et certaines ne fonctionnent qu'avec KSH.
Le caractère "*" permet de remplacer n'importe quel caractère.
$ ls
fichier1 fichier2.a monfichier tOnfichier.b
$ ls *.a
fichier2.a
$ ls f*
fichier1 fichier2.a
Le caractère "?" représente un caractère quelconque.
$ ls *.?
fichier2.a tOnfichier.b
$ ls ????????
fichier1
Les caractères "[ ]" permettent d'indiquer la liste des caractères que l'on recherche à une position bien précise dans le noms des fichiers.
$ ls [ft]*.[a-z]
fichier2.a tOnfichier.b
% ls ?[A-Z0-9e]*
cOucou f1chier F2chier Hello
$ ls [!a-z]*
1coucou Coucou F2chier Fichier Hello
% rm -i *.b *.c
rm : supprimer fichier vide «fichier1.b» ? y
rm : supprimer fichier vide «fichier1.c» ? y
Les expressions complexes sont compatible BASH à condition d'activer l'option extglob avec la commande shopt (shopt -s extglob).
$ ls
1coucou coucou.t fichier159159159.log fichier161.log fichier.log
cOucou coucou.uvw fichier159159.log fichier1.a Hello.txt
Coucou f1chier fichier159160.log fichier1.abc
coucou.r F2chier fichier159.log fichier1.b
coucou.s Fichier fichier160.log fichier1.c
L'expression sera présente 0 ou 1 fois.
Afficher tous les fichiers dont le nom contient 0 ou 1 fois "159"
$ ls fichier?(159).log
fichier159.log fichier.log
L'expression sera présente entre 0 et x fois.
Afficher tous les fichiers dont le nom contient 0 ou x fois "159"
$ ls fichier*(159).log
fichier159159159.log fichier159159.log fichier159.log fichier.log
L'expression sera présente entre 1 et x fois.
Afficher tous les fichiers dont le nom contient 1 ou x fois "159"
$ ls fichier+(159).log
fichier159159159.log fichier159159.log fichier159.log
L'expression sera présente exactement 1 fois.
Afficher tous les fichiers dont le nom contient 1 fois "159"
$ ls fichier@(159).log
fichier159.log
L'expression ne sera pas présente.
Afficher tous les fichiers dont le nom ne contient pas 1 fois "159"
$ ls fichier!(159).log
fichier159159159.log fichier159160.log fichier161.log
fichier159159.log fichier160.log fichier.log
Afficher tous les fichiers dont le nom ne contient pas "fichier"
$ ls !(fichier*)
1coucou Coucou coucou.s coucou.uvw F2chier Hello.txt
cOucou coucou.r coucou.t f1chier Fichier
Une barre verticale dans une expression correspond à "ou bien"
Afficher tous les fichiers dont le nom contient 1 fois "159" ou "160"
$ ls fichier@(159|160).log
fichier159.log fichier160.log
Afficher tous les fichiers dont le nom contient 1 ou x fois "159" ou "161"
$ ls fichier+(159|161).log
fichier159159159.log fichier159159.log fichier159.log fichier161.log
Afficher tous les fichiers dont le nom contient 1 fois ( 1 ou x fois "159" ou "161")
$ ls fichier@(+(159)|+(161)).log
fichier159159159.log fichier159159.log fichier159.log fichier161.log
Le caractère ";" permet d'écrire plusieurs commandes sur une même ligne. Toutes les commandes sont exécutées dans l'ordre.
$ pwd
/home/toto
$ ls
1coucou coucou.t fichier159159159.log fichier161.log fichier.log
cOucou coucou.uvw fichier159159.log fichier1.a Hello.txt
Coucou f1chier fichier159160.log fichier1.abc
coucou.r F2chier fichier159.log fichier1.b
coucou.s Fichier fichier160.log fichier1.c
$ mkdir tmp; chmod 755 tmp; chown toto:toto tmp; cd tmp; pwd
/home/toto/tmp
Les redirections sont souvent utilisées dans les commandes Linux.
Elles permettent de récupérer le résultat d'une ou plusieurs commandes dans un ou plusieurs fichiers ou de faire lire le contenu d'un fichier à une commande.
Les commandes Linux ont par défaut 3 descripteurs de fichier différent.
L'entrée standard d'une commande correspond au descripteur de fichier 0.
Les commandes qui attendent des informations de la part de l'utilisateur déclenche une requête de lecture sur le descripteur 0.
Par défaut, ce descripteur est associé au terminal et donc par une saisie au clavier.
La sortie standard d'une commande correspond au descripteur de fichier 1.
Le résultat d'une commande est, par défaut, affichée à l'écran via ce descripteur mais il peut être redirigé dans un fichier.
La sortie d'erreur standard d'une commande correspond au descripteur de fichier 2.
Quand une commande rencontre une erreur, celle-ci est retournée à l'écran via le descripteur 2 mais elle peut également être retournée dans un fichier.
Cette redirection permet d'écrire dans un fichier le résultat d'une commande au lieu de l'afficher à l'écran.
Simple redirection
$ commande > fichier
ou
$ commande 1> fichier
Si le fichier n'existe pas, il est automatiquement créé. S'il existe déjà, il est tout simplement écrasé.
Récupérer le résultat de la commande ls dans un fichier "liste"
$ ls > liste
$ cat liste
1coucou
cOucou
Coucou
Double redirection
Elle permet de concaténer le résultat d'une commande au contenu d'un fichier déjà existant.
$ commande >> fichier
ou
$ commande 1>> fichier
Si le fichier n'existe pas, il est automatiquement créé. S'il existe déjà, le résultat de la commande est ajouté au fichier.
$ pwd >> liste
$ cat liste
1coucou
cOucou
Coucou
/home/toto
Simple redirection
$ commande 2> fichier
$ ls /root 2> erreur
$ cat erreur
ls: impoossible d'ouvrir le répertoire /root: Permission non accordée
Double redirection
$ commande 2>> fichier
$ mkdir /root/tmp 2>> erreur
$ cat erreur
ls: impoossible d'ouvrir le répertoire /root: Permission non accordée
mkdir: impossible de créer le répertoire «/root/tmp»: Permission non accordée
Il est possible de rediriger plusieurs sorties sur une même ligne de commande.
$ commande 1> fichier1 2> fichier2
ou
$ commande 2> fichier2 1> fichier1
$ find /etc -name smb.conf 1> resultat 2> erreur
$ cat resultat
/etc/samba/smb.conf
$ cat erreur
find: "/etc/lvm/cache": Permission non accordée
find: "/etc/lvm/backup": Permission non accordée
find: "/etc/lvm/archive": Permission non accordée
Si l'on ne souhaite pas afficher et/ou enregistrer les erreurs retournées, il est possible de rediriger le descripteur 2 vers un fichier spécial existant sur tous les systèmes Linux "/dev/null"
$ find /etc -name smb.conf 1> resultat 2> /dev/null
$ cat resultat
/etc/samba/smb.conf
$ cat /dev/null
$
La redirection de l'entrée standard concerne toutes les commandes attendant une saisie de la part de l'utilisateur sur le descripteur 0 (saisie écran).
$ mail toto
>Coucou
>Comment vas tu ?
>^d (équivalent de CTRL+d)
$
La commande mail lit sur l'entrée standard toutes les données saisies à l'écran. La saisie se termine par la fonction CTRL+d.
Ensuite, la commande mail envoie ces données dans un message à l'utilisateur indiqué (toto).
Il est tout à fait possible d'écrire le contenu du message dans un fichier et de "l'injecter" à la commande mail sur son descripteur 0.
$ commande 0< fichier
ou
$ commande < fichier
$ echo "Coucou, comment vas tu ?" > message
$ cat message
Coucou, comment vas tu ?
$ mail toto < message
$ commande 1> fichier1 2>&1
ou
$ commande 2> fichier2 1>&2
Le principe consiste à écrire dans un fichier le résulat du descripteur 1 dans le fichier "fichier1" (1> fichier1) puis le résultat du descripteur 2 vers le descripteur 1 (2>&1) et par conséquent dans le fichier "fichier1".
$ find /etc -name smb.conf 1> resultat 2>&1
$ cat resultat
find: "/etc/lvm/cache": Permission non accordée
find: "/etc/lvm/backup": Permission non accordée
find: "/etc/lvm/archive": Permission non accordée
/etc/samba/smb.conf
Attention :
$ commande 2>&1 1> fichier1
Cette syntaxe n'agit pas de la même manière que les précédentes.
En effet, nous indiquons dans un premier temps de rediriger le descripteur 2 (sortie d'erreur standard) vers le descripteur 1, c'est à dire vers la sortie standard qui est, par défaut, l'affichage à l'écran, puis dans un second temps nous redirigeons le descripteur 1 (sortie standard) vers le fichier "fichier1".
En conclusion, tous les messages d'erreurs seront affichés à l'écran et le résulat de la commande dans le fichier "fichier1".
Cela revient à saisir :
$ commande 1> fichier1
Elle est principalement utilisée dans les scripts shell.
Elle permet de connecter l'entrée standard d'une commande sur une portion du script
Par exemple, avec la commande mail, cela permet de terminer la saisie du texte avec un caractère ou une chaine de caractère.
$ mail toto<<end
> bonjour
> ceci est un test
> end
$
Pour mettre fin à la commande mail, il suffit simplement de saisir l'expression inscrite juste après les doubles chevrons "<<". Dans l'exemple, la commande se termine après avoir saisi "end".
Identique à la fonction ^d (CTRL+d) en console.
Utilisation dans un script :
$ cat envoiMail.sh
#!/bin/sh
mail toto<<end
Bonjour,
Ceci est un test
Voici la liste des fichiers presents dans ton repertoire :
`ls -lhtr`
end
exit 0
Exécution du script
$ sh ./envoiMail.sh
Il est tout à fait possible de fermé un descripteur d'entrée ou de sortie en utilisant les symboles "<&-" ou ">&-" ou "2>&-".
Descripteur d'entrée standard "0" :
$ commande <&-
Descripteur de sortie standard "1" :
$ commande >&-
Descripteur de sortie d'erreur standard "2" :
$ commande 2>&-
Un tube de communication, ou pipe en anglais, permet de faire communiquer 2 commandes.
Ce "tube" est représenté par la barre verticale "|".
Le résultat de la commande de gauche est envoyé dans le tube et récupéré par la commande de droite.
C'est à dirte que la sortie standard "1" de la commande de gauche est connecté directement à l'entrée standard "0" de la commande de droite.
La sortie d'erreur standard "2" de la commande de gauche n'est pas envoyée dans le tube.
Pour que cette utilisation est un sens il faut impérativement que la commande de gauche utilise la sortie standard "1" et que la commande de droite utilise l'entrée standard "0".
Les commandes lisant leur entrée standard sont facilement identifiable car elles demandent une saisie au clavier.
Envoyer par mail la liste des users connectés :
$ who | mail toto
Envoyer par mail la liste des fichiers d'un répertoire :
$ ls -lht | mail toto
Envoyer un message à un utilisateur connecté au système :
$ echo "coucou, comment vas tu ?" | write tata
Afficher le nombre de fichiers d'un répertoire :
$ ls | wc -l
29
Envoyer par mail le nombre de fichiers d'un répertoire :
$ ls | wc -l | mail toto
Afficher avec pagination le contenu d'un fichier :
$ cat /etc/passwd | more
Lister le contenu d'un répertoire avec pagination :
$ ls -lht /etc | more
Afficher uniquement certains éléments d'un fichier :
$ cat /etc/passwd | grep root | cut -d':' -f1,7
root:/bin/bash
Envoyer par mail certains éléments d'un fichier :
$ cat /etc/passwd | grep root | cut -d':' -f1,7 | mail toto
Afficher à l'écran et enregistrer dans un fichier le contenu d'un répertoire :
$ ls -t | tee listeFichiers
listeFichiers
envoiMail.sh
message
script.sh
$ cat listeFichiers
listeFichiers
envoiMail.sh
message
script.sh
Il est donc tout à fait possible de cumuler autant de commandes que l'on souhaite à partir du moment où l'on respecte l'ordre des commandes et des sorties / entrées standard.
$ ls -l /root 2>&1 | tee listeFichiers
ls: impoossible d'ouvrir le répertoire /root: Permission non accordée
$ cat listeFichiers
ls: impoossible d'ouvrir le répertoire /root: Permission non accordée
Le regroupement de commandes est utilisé pour rediriger les sorties standards de plusieurs commandes vers un même fichier ou vers un tube ou pour exécuter des commandes dans un même environnement.
$ date ; ls > listeFichiers
lundi 19 septembre 2011, 08:47:11 (UTC+0200)
$ cat listeFichiers
1coucou
cOucou
Coucou
coucou.r
coucou.s
coucou.t
coucou.uvw
envoiMail.sh
Dans l'exemple ci-dessus, la commande date et ls sont regroupées grâce au caractère ";".
Le résultat de la commande date est affiché à l'écran alors que le résultat de la commande ls est redirigé dans le fichier "listeFichiers".
Afin de rediriger la sortie standard des 2 commandes au même endroit, ils faut obligatoirement les regroupées avec des parenthèses "()" ou des accolades "{}".
$ ( date ; ls ) > listeFichiers
$ cat listeFichiers
lundi 19 septembre 2011, 08:51:58 (UTC+0200)
1coucou
cOucou
Coucou
coucou.r
coucou.s
coucou.t
coucou.uvw
envoiMail.sh
Les commandes regroupées entre parenthèses sont exécutées par le shell enfant alors que les commandes regroupées entre accolades sont exécutées par le shell parent.
Regroupement avec parenthèses :
$ pwd
/home/toto
$ ( mkdir temp ; cd temp ; touch fichierTemp ; pwd ; ls ) > listeFichiers
$ cat listeFichiers
/home/toto/temp
fichierTemp
$ pwd
/home/toto
Après exécution des commandes, le répertoire courant est le même qu'avant exécution.
Regroupement avec accolades :
$ pwd
/home/toto
$ { mkdir temp ; cd temp ; touch fichierTemp ; pwd ; ls ; } > listeFichiers
$ pwd
/home/toto/temp
$ cat ../listeFichiers
/home/toto/temp
fichierTemp
Après exécution des commandes, le répertoire courant n'est plus le même qu'avant exécution.
Généralement, le regroupement entre parenthèses est plus utilisé que le regroupement entre accolades car la syntaxe est plus simple et cela ne modifie pas le shell courant mais pour un gain de performances le regroupement entre accolades est préférable.
Pour exécuter des commandes en arrière-plan, il suffit de rajouter à la fin le caractère "&".
Cela permet de récupérer le shell aussitôt après sans être obligé d'attendre la fin de l'exécution de la commande précédente.
Par contre, il est préférable d'utiliser la redirection de la sortie standard et de la sortie d'erreur standard.
$ find /etc -name passwd 1>listePasswd 2>/dev/null &
$ echo "On peut saisir d'autre commandes en attendant de voir le message ci-dessous une fois le processus terminé"
[1]+ Exit 1 find /etc -name passwd > listePasswd 2> /dev/null
$ cat listePasswd
/etc/passwd
/etc/webmin/passwd
/etc/pam.d/passwd
Le commande set permet d'obtenir la liste des variables paramétrées pour le shell courant.
$ set
BASH=/bin/bash
HOME=/home/toto
HOSTNAME=myhostname
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
PS1='\[\e]0;\u@\h: \w\a\]${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h$
PS2='> '
PS4='+ '
SHELL=/bin/bash
...
Le caractère $ permet d'obtenir la valeur d'une variable :
$ echo $BASH
/bin/bash
Pour créer ou modifier une variable :
$ VARIABLE='valeur'
$ echo $VARIABLE
valeur
Attention, car toutes variables créées ou modifiées de cette manière ne sont valables que pour la session en cours.
$ MAVARIABLE='<= Ceci est le contenu de ma variable =>'
$ echo $MAVARIABLE
<= Ceci est le contenu de ma variable =>
Les principales variables :
HOME : cette variable contient le chemin du répertoire d'accueil de l'utilisateur.
PATH : cette variable contient une liste de répertoire dans lesquels le shell recherche toutes les commandes qui sont exécutées.
Si une commande est exécutée et qu'elle ne se trouve dans aucun des répertoires indiqués dans la variable PATH, une erreur sera retournée en indiquant que la commande est introuvable.
Si l'on souhaite exécuter une commande qui se trouve dans un répertoire non indiqué dans la variable PATH, il suffit tout simplement de modifier le contenu de la variable.
$ PATH=$PATH:/leRepertoireDeMaCommande
Pour modifier la variable PATH définitivement, il suffit d'ajouter une ligne au fichier ~/.bashrc :
> export PATH=$PATH:/mon_autre_repertoire
Ou modifier directement le fichier /etc/environment :
> PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/mon_autre_repertoire"
Pour exécuter une commande présente dans le répertoire courant, il suffit d'ajouter à la variable PATH la valeur ":." ou ":".
PWD : cette variable contient le chemin du répertoire courant.
PS1 : cette variable contient la chaine de caractères correspondant au prompt ($ en règle générale).
Pour faire apparaitre la valeur du répertoire courant dans le prompt :
$ PS1='$PWD$ '
ou
$ PS1='\w$ '
BASH : Séquence d'échappement permettant de paramétrer la variable PS1
Séquence échappement | Valeur |
---|---|
\u | Nom de l'utilisateur |
\h | Nom de la machine |
\w | Répertoire courant |
\W | Partie terminale du répertoire courant |
PS2 : cette variable contient la chaine de caractères correspondant au prompt secondaire (> en règle générale).
$ echo 'ceci est le début
> de ma chaine de texte
> et tant que je ne saisi pas
> le caractère apostrophe
> ça continue
> '
ceci est le début
de ma chaine de texte
et tant que je ne saisi pas
le caractère apostrophe
ça continue
$
$ mail toto<<fin
> un autre exemple
>
> fin
$
TERM : cette variable contient le type du terminal de l'utilisateur.
LOGNAME : cette variable contient le nom de l'utilisateur connecté.
Il est parfois nécessaire d'exporter une variable car toutes ne le sont pas.
Pour savoir quelles sont les variables exportées d'office il suffit d'utiliser la commande env.
$ env
TERM=xterm
SHELL=/bin/bash
CDPATH=:.:/home/
USER=toto
...
Pour exporter une variable :
$ MAVARIABLE='maValeur'
$ export MAVARIABLE
ou
$ export MAVARIABLE='maValeur'
Par exemple, en BASH, pour utiliser le programme nano (éditeur de texte) comme éditeur par défaut du programme mutt (client mail en ligne de commande), il suffit d'inscrire dans son fichier ~/.bashrc :
export EDITOR=/usr/bin/nano
et pour une prise en compte immédiate, sans être obligé de se reconnecter, saisir dans la console :
$ export EDITOR=/usr/bin/nano
Et pour vérifier :
$ set | grep EDITOR
EDITOR=/usr/bin/nano
$ env | grep EDITOR
EDITOR=/usr/bin/nano
Pour activer ou désactiver les options du shell, il suffit d'utiliser la commande set avec les options -o et +o.
Activation :
$ set -o option
Désactivation :
$ set +o option
Pour visualiser la liste des options disponibles ainsi que leur état, saisir dans une console :
$ set -o
allexport off
braceexpand on
emacs on
errexit off
errtrace off
functrace off
hashall on
histexpand on
history on
ignoreeof off
interactive-comments on
keyword off
monitor on
noclobber off
noexec off
noglob off
nolog off
notify off
nounset off
onecmd off
physical off
pipefail off
posix off
privileged off
verbose off
vi off
xtrace off
Détails de certaines options :
Pour quitter le shell, il existe 3 méthodes :
Si l'option ignoreeof est activée, il n'est plus possible de quitter le shell en appuyant sur ^d.
Quand une redirection est faite vers un fichier déjà existant, celui-çi est automatiquement écrasé sans confirmation. Pour inverser se fonctionnement, il suffit d'activer l'option noclobber.
On vérifie l'état de l'option noclobber
$ set -o | grep noclobber
noclobber off
On redirige le résultat de la commande ls vers le fichier liste
$ ls -l > liste
On redirige le résultat de la commande pwd vers le fichier liste déjà existant
$ pwd > liste
On active l'option noclobber
$ set -o noclobber
On vérifie que l'option noclobber est bien activée
$ set -o | grep noclobber
noclobber on
On redirige le résultat de la commande pwd vers le fichier liste déjà existant
$ pwd > liste
-bash: liste : impossible d'écraser le fichier existant
On force la redirection de la commande pwd vers le fichier liste déjà existant
$ pwd >| liste
Ces 2 options permettent de paramétrer le rappel des commandes.
En ksh, ces 2 options sont désactivées.
En bash, seule l'option emacs est activée.
Cette option est utilisée pour déboguer les scripts shell.
Les alias permettent de créer des raccourcis vers des commandes et de les personnaliser.
Pour visualiser la liste des alias déjà existant :
$ alias
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l='ls -CF'
alias la='ls -A'
alias ll='ls -lF'
alias ls='ls --color=auto'
alias tarc='tar -cvzf'
alias tarx='tar -xvzf'
Pour visualiser un alias en particulier :
$ alias la
alias la='ls -A'
Pour créer un alias :
$ alias c='clear'
$ alias rm='rm -i'
$ rm liste
rm : supprimer fichier «liste» ? y
En bash, pour créer un alias définitivement, il suffit de le renseigner dans le fichier ~/.bashrc
Pour supprimer un alias :
$ unalias c
$ c
c : commande introuvable
Le shell enregistre toutes les commandes saisies dans un fichier texte.
En bash, il s'agit du fichier ~/.bash_history
En ksh, il s'agit du fichier ~/.sh_history
Pour utiliser le rappel des commandes, le shell utilise soit emacs soit vi.
En bash, c'est l'option emacs qui est activée par défaut mais il est possible d'utiliser vi.
En ksh, les 2 options sont par défaut désactivées.
Le choix d'activer l'un, désactive l'autre.
$ set -o | grep "^emacs\|^vi"
emacs on
vi off
Pour les utilisateurs non habitués à l'éditeur vi, il est préférable d'utiliser emacs car le rappel des commandes se fait avec les flèches du clavier.
Les fichiers d'environnement sont utilisés pour stocker de manière permanente tout le paramétrage de l'environnement de l'utilisateur.
Ce sont des scripts shell qui contiennent un ensemble de commandes Linux.
Certains scripts sont exécutés uniquement par le shell de connexion et d'autres par un shell ordinaire.
Le shell de connexion est lancé immédiatement après l'identification de l'utilisateur.
Le shell de connexion exécute en premier le script /etc/profile. Ce script contient le paramétrage commun à tous les utilisateurs.
Il recherche ensuite dans le répertoire d'accueil de l'utilisateur un script dont le nom dépend du shell utilisé.
En sh / ksh :
Le script de connexion se nomme ~/.profile
En bash :
L'un des 3 scripts suivants dans l'ordre
En bash, le shell de connexion exécute en premier le script /etc/profile, puis le script ~/.profile et enfin le script ~/.bashrc.
C'est dans ce dernier fichier, ~/.bashrc, que l'on peut définir de nouveaux alias, exporter automatiquement de nouvelles variables, paramétrer l'auto-complétion, définir les variables PS1 et PS2, paramétrer le nombre de commandes à historiser, etc etc.
Le shell permet de définir ou redéfinir des variables pour l'environnement de l'utilisateur.
Il est également possible de définir d'autres variables dites variables utilisateur qui vont permettre de stocker des informations utiles durant l'exécution de scripts.
$ variable1=valeur1
$ echo $variable1
valeur1
$
Il ne faut surtout pas mettre d'espace avant et après le signe égal (=) ainsi que dans la valeur de la variable.
Si un espace est placé avant le signe '=', le shell va interpréter la chaine 'variable1' comme étant une commande et la chaine '=valeur1' comme étant un paramètre de la commande variable1.
Pour pouvoir affecter une valeur contenant un espace, il faut obligatoirement le protéger avec des simples quotes.
$ variable2='valeur2 valeur21'
$ echo $variable2
valeur2 valeur21
$
Pour supprimer le contenu d'une variable, il faut utiliser la commande unset :
$ variable3=valeur3
$ echo $variable3
valeur3
$ set | grep variable3
variable3=valeur3
$ unset variable3
$ echo $variable3
$ set | grep variable3
$
Concaténer des variables avec une chaine de caractères :
Un exemple qui produit une erreur
$ fichier=monFichier
$ dateJour=20111006
$ nouveauFichier=$fichier_$dateJour
$ echo $nouveauFichier
20111006
$
Le but de cet exemple est de concaténer la variable $fichier, un tiret bas '_', puis la variable $dateJour.
Le résultat final est erroné car au moment d'affecter la nouvelle variable nouveauFichier (ligne 3), le shell interprète $fichier_ comme étant une variable à part entière puisque le tiret bas '_' est autorisé dans le nommage des variables.
La variable $fichier_ n'existant pas, celle ci est égale à "blanc".
Pour indiquer au shell qu'il faut interpréter le tiret bas '_' comme étant une chaine de caractères, il faut obligatoirement entourer la variable qui le précède avec des {}.
$ fichier=monFichier
$ dateJour=20111006
$ nouveauFichier=${fichier}_$dateJour
$ echo $nouveauFichier
monFichier_20111006
$
Substituer des variables :
Le shell offre la possibilité d'attribuer une valeur par défaut aux variables non initialisées ou au contraire initialisées.
Expression ${variable:-valeur}
$ jour=mardi
$ echo "Nous sommes : ${jour:-dimanche}"
Nous sommes : mardi
$ unset jour
$ echo "Nous sommes : ${jour:-dimanche}"
Nous sommes : dimanche
$ echo $jour
$
Expression ${variable:=valeur}
$ jour=mardi
$ echo "Nous sommes : ${jour:=dimanche}"
Nous sommes : mardi
$ echo $jour
mardi
$ unset jour
$ echo "Nous sommes : ${jour:=dimanche}"
Nous sommes : dimanche
$ echo $jour
dimanche
$
Expression ${variable:+valeur}
$ bool=1
$ echo "Si bool=1 alors j'affiche : ${bool:+true}"
Si bool=1 alors j'affiche : true
$ unset bool
$ echo "Si bool=1 alors j'affiche : ${bool:+true}"
Si bool=1 alors j'affiche :
$
Expression ${variable:?message}
Dans un script, si la variable est vide, le message est affiché et le script se termine aussitôt
$ nombre=56
$ echo ${nombre:?"nombre indefini"}
56
$ unset nombre
$ echo ${nombre:?"nombre indefini"}
-bash: nombre: nombre indefini
Affichage du message par défaut
$ echo ${nombre:?}
-bash: nombre : parametre vide ou non defini
$
Les caractères de substitution permettent de remplacer une commande par le résultat de son exécution.
Par exemple, comment faire pour afficher un message affichant la date du jour.
$ echo "Nous sommes le date"
Nous sommes le date
$
Il suffit d'entourer la commande avec les caractères de substitution :
$ echo "Nous sommes le `date`"
Nous sommes le vendredi 7 octobre 2011, 08:39:49 (UTC+0200)
$ echo "Nous sommes le $(date)"
Nous sommes le vendredi 7 octobre 2011, 08:40:05 (UTC+0200)
$
Idem pour initialiser une variable :
$ date=`date`
$ echo $date
vendredi 7 octobre 2011, 08:42:34 (UTC+0200)
$
Les caractères de protection servent à utiliser les caractères spéciaux du shell comme n'importe quels caractères.
Les simples quotes désactivent tous les caractères spéciaux du shell. Ils doivent être utilisés en nombre pair sur une ligne de commande.
$ echo $PWD
/home/toto
Avec les simples quotes, la fonction du caractère '$' est désactivée :
$ echo '$PWD'
$PWD
$
Afficher tous les fichiers d'un dossier à l'aide de la fonction 'echo' et du caractère spécial '*'
$ echo *
1coucou cOucou Coucou coucou.r ...
Avec les simples quotes, la fonction du caractère '*' est désactivée :
$ echo '*'
*
$
$ echo Bonjour $(logname)
Bonjour toto
$ echo 'Bonjour $(logname)'
Bonjour $(logname)
$
La quote ne se protège pas elle-même.
Tant que les quotes ne sont pas par pair, le shell affiche le prompt secondaire
$ echo 'J'affiche un quote supplémentaire'
>
L'antislash désactive la fonctionnalité du caractère qui le suit.
$ echo La liste des fichiers * du dossier $PWD
La liste des fichiers 1coucou cOucou Coucou coucou.r du dossier /volume1/home/ronan/atuer/toto
$ echo La liste des fichiers \* du dossier \$PWD
La liste des fichiers * du dossier $PWD
$
L'antislash se protège lui-même
$ echo \\
\
$
$ echo L\'antislash protège la quote
L'antislash protège la quote
$
Le premier antislash protège le second, le troisième protège le '$'
$ echo \\\$PWD
\$PWD
$
Les guillemets protège tous les caractères spéciaux du shell à l'exception du dollar $, des quotes inversés ``, du dollar et des parenthèses $( ), de l'antislash \ et des guillemets ".
$ echo "
> La variable \$HOME est substituée par $HOME
> La commande \$(logname) est exécutée : $(logname)
> Je peux afficher des > et des |
> Et même des guillemets \"."
La variable $HOME est substituée par /home/toto
La commande $(logname) est exécutée : toto
Je peux afficher des > et des |
Et même des guillemets ".
$
En règle générale, il est préférable d'utiliser la commande echo avec des guillemets
Caractères | Signification |
---|---|
espace - tabulation - saut de ligne | Séparateurs de mots sur la ligne de commande |
& | Arrière-plan |
| << < > >> | Tubes et redirections |
() et {} | Regroupement de commandes |
; | Séparateur de commandes |
* ? [ ] ?( ) +( ) *( ) !( ) @( ) | Caractères de génération de noms de fichier |
$ et ${ } | Valeur d'une variable |
`` $( ) | Substitution de commandes |
' ' " " \ | Caractères de protection |
Les caractères spéciaux du shell sont interprétés dans un ordre bien précis.
$ echo "\$HOME --> $HOME
> Mon login --> $(logname)
> Nous sommes le `date`
> La liste des fichiers :" * | nl > test ; cat test
1 $HOME --> /home/toto
2 Mon login --> toto
3 Nous sommes le jeudi 20 octobre 2011, 08:27:05 (UTC+0200)
4 La liste des fichiers : fichier1 fichier2 fichier3 fichier4
$
Un script shell est un fichier texte contenant des commandes Linux internes ou externes.
Le nom du script peut avoir une extension mais cela n'est pas obligatoire.
En règle générale, tous les scripts portent l'extension .sh
Exemple :
$ nl monPremierScript.sh
1 pwd
2 echo "Liste des fichiers commençant par la lettre C"
3 ls -lh c*
$
Exécution :
$ bash monPremierScript.sh
/home/toto
Liste des fichiers commençant par la lettre C
-rw-r--r-- 1 toto toto 0 2011-09-14 13:55 cOucou
-rw-r--r-- 1 toto toto 0 2011-09-15 07:20 coucou.r
-rw-r--r-- 1 toto toto 0 2011-09-15 07:20 coucou.s
-rw-r--r-- 1 toto toto 0 2011-09-15 07:20 coucou.t
-rw-r--r-- 1 toto toto 0 2011-09-15 07:21 coucou.uvw
$
Il existe 3 méthodes pour exécuter un script.
La première méthode consiste à appeler la commande bash, sh, ksh etc.. (l'interpréteur de commande désiré) suivi du nom du script.
$ bash monPremierScript.sh
Dans ce cas, le droit de lecture sur le fichier est suffisant.
$ ls -l monPremierScript.sh
-rw-r--r-- 1 toto toto 68 2011-10-20 08:52 monPremierScript.sh
$
La seconde méthode consiste à utiliser l'entrée standard de la commande bash, sh, ksh etc.. afin de lui faire lire le contenu du script.
$ bash < monPremierScript.sh
Dans ce cas, le droit de lecture sur le fichier est également suffisant.
Cette méthode est très peu utilisée.
La troisième méthode consiste à rendre le script exécutable.
$ chmod u+x monPremierScript.sh
$ ls -l monPremierScript.sh
-rwxr--r-- 1 toto toto 68 2011-10-20 08:52 monPremierScript.sh
$ ./monPremierScript.sh
Choisir un interpréteur de commande :
Pour indiquer au script quel interpréteur de commande utiliser, il faut indiquer sur la première ligne du script les caractères #! suivi du chemin absolu de l'interpréteur.
Par exemple, pour utiliser l'interpéteur de commande BASH, on recherche son chemin absolu :
$ whereis bash
bash: /bin/bash /etc/bash.bashrc /usr/share/man/man1/bash.1.gz
$
La résultat de la commande nous indique le répertoire /bin/bash
Inscrire sur la première ligne du script #! /bin/bash
$ nl monPremierScript.sh
1 #! /bin/bash
2 pwd
3 echo "Liste des fichiers commençant par la lettre C"
4 ls -lh c*
$
De cette manière, le script sera toujours exécuté avec l'interpréteur de commande BASH.
L'exécution d'un script par le shell courant permet de modifier l'environnement du shell courant.
Les droits d'exécution sur le script ne sont pas nécessaires.
L'utilisation de la commande interne "." est nécessaire pour l'exécution.
Par exemple, pour modifier l'éditeur par défaut, il est nécessaire de modifier la variable environnement EDITOR.
$ env | grep EDITOR
EDITOR=/usr/bin/vi
$ echo $EDITOR
/usr/bin/vi
$ nano .profile
export EDITOR='/usr/bin/nano'
^o (enregistrer)
^x (quitter)
$ . .profile
$ echo $EDITOR
/usr/bin/nano
$ env | grep EDITOR
EDITOR=/usr/bin/nano
$
Attention, l'appel de la commande interne "." est obligatoirement suivi d'un espace et d'un script shell.
Il est possible d'écrire dans un script des commentaires afin de faciliter la compréhension du script.
Les commentaires sont désignés à l'aide du caractère #.
Ne pas confondre avec #! inscrit sur la première ligne du script qui sert à renseigner l'interpréteur de commande.
$ nl monPremierScript.sh
1 #! /bin/bash
2 # Ceci est un commentaire
3 # La commande PWD indique le répertoire courant
4 pwd
5 # La commande ECHO permet d'afficher du texte et des informations
6 echo "Liste des fichiers commençant par la lettre C"
7 # La commande LS permet de lister tous les fichiers commençant par la lettre "c"
8 ls -lh c*
$
Dans un script, il est possible de récupérer en lecture un certain nombre de variables réservées.
Ces variables sont initialisées par le shell et contiennent des informations diverses et variées.
Les scripts shell sont capables de récupérer des arguments placés juste après l'appel du script.
En KSH et en BASH, il est possible d'aller au delà de 9 arguments en utilisant les variables spéciales ${10}, ${11} etc...
Les accolades sont obligatoires à partir du moment où le nom de la variable contient plus d'un chiffre.
Exemple :
$ nano monSecondScript.sh
#! /bin/bash
echo "Il y a $# arguments passés au script"
echo "Le script se nomme $0"
echo "La valeur du premier argument : $1"
echo "La valeur du second argument : $2"
echo "La valeur du troisième argument : $3"
echo "Les valeurs de tous les arguments : $*"
^o (enregistrer)
^x (quitter)
$ chmod u+x monSecondScript.sh
$ ./monSecondScript.sh arg1 arg2 arg3 arg4 arg5
Il y a 5 arguments passés au script
Le script se nomme ./monSecondScript.sh
La valeur du premier argument : arg1
La valeur du second argument : arg2
La valeur du troisième argument : arg3
Les valeurs de tous les arguments : arg1 arg2 arg3 arg4 arg5
$
Exemple avec 3 arguments :
$ ./monSecondScript.sh 25 + 15
Il y a 3 arguments passés au script
Le script se nomme ./monSecondScript.sh
La valeur du premier argument : 25
La valeur du second argument : +
La valeur du troisième argument : 15
Les valeurs de tous les arguments : 25 + 15
$
Tous les arguments doivent être séparés les uns des autres par un espace ou une tabulation
La commande shift permet de décaler la liste des arguments d'une ou plusieurs positions vers la gauche.
Cette commande est utilisée dans le cas où le premier argument n'a pas à subir le même traitement que les suivants.
Dans ce cas, le premier argument doit être sauvegardé dans une variable et l'exécution de la commande shift entraine le remplacement du premier argument par le second et ainsi de suite.
$ nl monTroisiemeScript.sh
1 #! /bin/bash
2 # Ce script doit recevoir en premier argument le nom d'un dossier puis des noms de fichiers pour les suivants
3 # Affichage des variables avant l'utilisation de la commande shift
4 echo -e "Affichage avant exécution de la commande shift\n"
5 echo "1er argument \$1 : $1"
6 echo "1er argument \$2 : $2"
7 echo "1er argument \$3 : $3"
8 echo "1er argument \$4 : $4"
9 echo "Tous les arguments \$* : $*"
10 echo -e "Le nombre d'argument \$# : $#\n"
11 # On sauvegarde le premier argument dans la variable rep
12 rep=$1
13 # On décale tous les arguments avec la commande shift
14 shift
15 # Affichage des variables après l'exécution de la commande shift
16 echo -e "Affichage après exécution de la commande shift\n"
17 echo "1er argument \$1 : $1"
18 echo "1er argument \$2 : $2"
19 echo "1er argument \$3 : $3"
20 echo "1er argument \$4 : $4"
21 echo "Tous les arguments \$* : $*"
22 echo -e "Le nombre d'argument \$# : $#\n"
23 # Création du répertoire
24 mkdir $rep
25 # On se positionne dans le nouveau répertoire
26 cd $rep
27 # Création des fichiers dans le nouveau répertoire
28 for fichier in $*
29 do
30 touch $fichier
31 done
$ chmod u+x monTroisiemeScript
Exécution du script :
$ ./monTroisiemeScript.sh test fic1 fic2 fic3 fic4 fic5 fic6
Affichage avant exécution de la commande shift
1er argument $1 : test
1er argument $2 : fic1
1er argument $3 : fic2
1er argument $4 : fic3
Tous les arguments $* : test fic1 fic2 fic3 fic4 fic5 fic6
Le nombre d'argument $# : 7
Affichage après exécution de la commande shift
1er argument $1 : fic1
1er argument $2 : fic2
1er argument $3 : fic3
1er argument $4 : fic4
Tous les arguments $* : fic1 fic2 fic3 fic4 fic5 fic6
Le nombre d'argument $# : 6
$ ls -l ./test/
total 0
-rw-r--r-- 1 toto toto 0 2011-10-25 09:01 fic1
-rw-r--r-- 1 toto toto 0 2011-10-25 09:01 fic2
-rw-r--r-- 1 toto toto 0 2011-10-25 09:01 fic3
-rw-r--r-- 1 toto toto 0 2011-10-25 09:01 fic4
-rw-r--r-- 1 toto toto 0 2011-10-25 09:01 fic5
-rw-r--r-- 1 toto toto 0 2011-10-25 09:01 fic6
$
Toutes les commandes Linux retournent un code d'erreur compris entre 0 et 255.
La valeur 0 représente la valeur vrai (succès de la commande).
Les valeurs supérieur à 0 représente la valeur faux (échec de la commande).
Le code erreur de la dernière commande utilisée est contenu dans la variable $?
$ ls f*
f1chier fichier159159.log fichier159.log fichier161.log fichier1.abc fichier1.c fset
fichier159159159.log fichier159160.log fichier160.log fichier1.a fichier1.b fichier.log
$ echo $?
0
$ ls 2*
ls: impossible d'accéder à 2*: Aucun fichier ou dossier de ce type
$ echo $?
2
Dans un script shell, le test du code de retour d'une commande permet d'effectuer différentes actions.
Un script shell étant lui-même une commande, il est possible de lui faire retourner un code d'erreur avec la commande exit.
Par exemple, il est possible d'indiquer dans un script exit 1 afin d'indiquer une erreur rencontrée et/ou exit 0 afin d'indiquer que tout c'est bien déroulé.
Dans l'exemple suivant, le script test s'il reçoit bien au minimum 2 arguments et renvoi le code erreur 1 si c'est faux.
$ nl ./script.sh
1 #! /bin/bash
2 # Le script doit recevoir au minimum 2 arguments
3 if [ $# -lt 2 ]
4 then
5 # Si le nombre d'arguments est inférieur à 2
6 # on retourne le code erreur 1
7 echo "Nombre arguments incorrect"
8 exit 1
9 else
10 # Si le nombre d'arguments est supérieur ou égal à 2
11 # on retourne le code erreur 0
12 echo "Nombre arguments correct"
13 exit 0
14 fi
$
Exécution du script :
$ ./script.sh
Nombre arguments incorrect
$ echo $?
1
$ ./script.sh test
Nombre arguments incorrect
$ echo $?
1
$ ./script.sh test test2
Nombre arguments correct
$ echo $?
0
$
La variable $$ représente le PID du shell qui interprète le script.
La valeur de cette variable est la même pendant toute la durée d'exécution du script et différente à chaque utilisation du script.
Exemple :
Dans ce script, la variable $$ est utilisée pour générer le nom d'un dossier différent à chaque exécution du script.
$ nl monQuatriemeScript.sh
1 #! /bin/bash
2 dossierTemp=dossier_$$
3 echo "Création du dossier \"$dossierTemp\""
4 mkdir $dossierTemp
5 cd $dossierTemp
6 for (( i=0 ; i<10 ; i++)) do
7 touch fichier_$i
8 done
9 exit 0
$
$ ./monQuatriemeScript.sh
Création du dossier "dossier_26563"
$ ./monQuatriemeScript.sh
Création du dossier "dossier_26581"
$
La variable $! représente le PID d'une commande exécutée en arrière plan.
exemple :
$ nl monCinquiemeScript.sh
1 #! /bin/bash
2 echo "Le script est exécuté sous le PID $$"
3 find /etc -name $1 1> resultat 2> /dev/null &
4 echo "La commande FIND est en cours d'exécution sous le PID $!"
5 ps
6 exit 0
$
$ ./monCinquiemeScript.sh hosts.allow
Le script est exécuté sous le PID 29999
La commande FIND est en cours d'exécution sous le PID 30000
PID TTY TIME CMD
19703 pts/0 00:00:00 bash
29999 pts/0 00:00:00 monCinquiemeScr
30000 pts/0 00:00:00 find
30001 pts/0 00:00:00 ps
$
La commande read lit son entrée standard et affecte les valeurs saisies dans la ou les variables passées en argument.
$ read var1
coucou
$ echo $var1
coucou
$
Tous les mots saisis sont stockés dans la variables var1
$ read var1
coucou tout le monde
$ echo $var1
coucou tout le monde
$
Le premier mot est stocké dans var1 et le second dans var2
$ read var1 var2
A bientot
$ echo $var1
A
$ echo $var2
bientot
$
Le premier mot est stocké dans var1 et les autres dans var2
$ read var1 var2
A bientot tout le monde
$ echo $var1
A
$ echo $var2
bientot tout le monde
$
Le mot est stocké dans var1 et var2 est vide
$ read var1 var2
Bonjour
$ echo $var1
Bonjour
$ echo $var2
$
En KSH, il est possible d'associer un message à la commande read
$ read var1?"Saisir une valeur : "
Saisir une valeur : coucou
$ echo $var1
coucou
$
Le code retour de la commande read est vrai (0) si un texte est saisi et faux (1) si la commande est interrompue en appuyant sur ctrl+d (^d)
$ read var1
coucou
$ echo $?
0
$ echo $var1
coucou
$
$ read var1
[Entrée]
$ echo $?
0
$ echo $var1
$
$ read var1
$ ^d
$ echo $?
1
$ echo $var1
$
Cette variable contient les caractères qui permettent de scinder les entrées au clavier.
Par défaut elle contient les caractères espace, tabulation (\t) et saut de ligne (\n)
Le contenu de cette variable peut être modifié
$ OLDIFS="$IFS"
$ IFS="|" # modification du caractère de séparation
$ read var1 var2 var3
colonne1|colonne2|colonne3
$ echo $var1
colonne1
$ echo $var2
colonne2
$ echo $var3
colonne3
$ IFS="$OLDIFS"
$
Les expression $IFS et $OLDIFS doivent obligatoirement être placées entre guillemets pour que les caractères internes ne soient pas interprétés par le shell
En BASH, il est possible d'associer un message à la commande read grâce à l'option -p :
$ read -p "Votre nom ? " NAME
Votre nom ? toto
$ echo $NAME
toto
En y ajoutant l'option -s , il est possible d'utiliser la commande read pour saisir un mot de passe :
$ read -s -p "Votre passwd ? " PASSWD; echo
Votre passwd ?
$ echo $PASSWD
aaaa
Avec l'option -s, il ne faut pas oublier d'ajouter la commande echo pour afficher un saut de ligne.
La commande test permet de faire des tests sur des fichiers, des chaines de caractères et des nombres.
Elle renvoie le code retour 0 (vrai) ou 1 (faux) qu'il est possible de consulter en affichant la valeur de $?
Il existe 2 syntaxes pour utiliser la commande test
$ test expression
$ [ expression ]
La paire de crochet signifie la même chose que la commande test.
Les crochets ouvrants et fermants doivent obligatoirement être suivis et précédés d'un espace.
Expression | Code de retour |
---|---|
-b FILE | Vrai si le fichier existe et est du type spécial bloc |
-c FILE | Vrai si le fichier existe et est du type spécial caractère |
-d FILE | Vrai si le fichier existe et est du type répertoire |
-e FILE | Vrai si le fichier existe |
-f FILE | Vrai si le fichier existe et est du type ordinaire |
-G FILE | Vrai si le fichier existe et si l'utilisateur appartient au groupe propriétaire du fichier |
-h FILE | Vrai si le fichier existe et est du type lien symbolique |
-L FILE | Vrai si le fichier existe et est du type lien symbolique (idem -h) |
-O FILE | Vrai si le fichier existe et si l'utilisateur est le propriétaire du fichier |
-r FILE | Vrai si le fichier existe et est accessible en lecture |
-s FILE | Vrai si le fichier existe et n'est pas vide |
-S FILE | Vrai si le fichier existe et est du type socket |
-w FILE | Vrai si le fichier existe et est accessible en écriture |
-x FILE | Vrai si le fichier existe et est exécutable |
FILE1 -ef FILE2 | Vrai si les fichiers ont le même lien physique |
FILE1 -nt FILE2 | Vrai si FILE1 est plus récent que FILE2 |
FILE1 -ot FILE2 | Vrai si FILE1 est plus ancien que FILE2 |
Exemple :
Le fichier /etc/group est un fichier ordinaire
$ test -f /etc/group
$ echo $?
0
$
Le fichier /etc/groupe n'existe pas (test avec l'autre syntaxe)
$ [ -f /etc/groupe ]
$ echo $?
1
$
Le fichier /etc/init.d existe et est un répertoire
$ [ -d /etc/init.d ]
$ echo $?
0
$
Le fichier /etc/group n'est pas un répertoire ou il n'exsite pas
$ test -d /etc/group
$ echo $?
1
$
Le fichier contenu dans la variable file n'est pas un répertoire ou n'existe pas
$ file=/etc/group
$ test -d $file
$ echo $?
1
$
L'utilisateur n'a pas le droit d'écriture sur le fichier /etc/group
$ [ -w /etc/group ]
$ echo $?
1
$
Expression | Code de retour |
---|---|
-n STRING | Vrai si la longueur de la chaine n'est pas égale à 0 |
-z STRING | Vrai si la longueur de la chaine est égale à 0 |
STRING1 = STRING2 | Vrai si les 2 chaines sont égales |
STRING1 != STRING2 | Vrai si les 2 chaines sont différentes |
STRING | Vrai si la chaine n'est pas vide (idem -n) |
Pour les tests sur les chaines de caractères, il est recommandé de mettre le nom des variables entre guillemets.
Exemple :
Avec les variables suivantes :
$ str1="test1"
$ str2="test2"
$ str3="test1"
$
La variable $str1 n'est pas vide
$ [ -n "$str1" ]
$ echo $?
0
$
$ [ "$str1" ]
$ echo $?
0
$ [ -z "$str1" ]
$ echo $?
1
$
La variable $str4 est vide
$ [ -n "$str4" ]
$ echo $?
1
$
$ [ -z "$str4" ]
$ echo $?
0
$
$ [ "$str4" ]
$ echo $?
1
$
$str1 & $str3 sont identiques
$ [ "$str1" = "$str3" ]
$ echo $?
0
$
$ [ "$str1" != "$str3" ]
$ echo $?
1
$
$str1 & $str2 sont différentes
$ [ "$str1" != "$str2" ]
$ echo $?
0
$
$ [ "$str1" = "$str2" ]
$ echo $?
1
$
Expression | Code de retour |
---|---|
INT1 -eq INT2 | Vrai si INT1 est égal à INT2 (=) |
INT1 -ge INT2 | Vrai si INT1 est supérieur ou égal à INT2 (>=) |
INT1 -gt INT2 | Vrai si INT1 est supérieur à INT2 (>) |
INT1 -le INT2 | Vrai si INT1 est inférieur ou égal à INT2 (<=) |
INT1 -lt INT2 | Vrai si INT1 est inférieur à INT2 (<) |
INT1 -ne INT2 | Vrai si INT1 est différent de INT2 (!=) |
Exemple :
Avec les variables suivantes
$ int1=1
$ int2=2
$ int3=3
$ int4=2
$
$int2 & $int4 sont égaux
$ [ $int2 -eq $int4 ]
$ echo $?
0
$int2 est supérieur ou égal à $int4
$ [ $int2 -ge $int4 ]
$ echo $?
0
$int3 est supérieur ou égal à $int1
$ [ $int3 -ge $int1 ]
$ echo $?
0
$int4 n'est pas supérieur ou égal à $int3
$ [ $int4 -ge $int3 ]
$ echo $?
1
$int3 est supérieur à $int2
$ [ $int3 -gt $int2 ]
$ echo $?
0
$int2 n'est pas supérieur à $int3
$ [ $int2 -gt $int3 ]
$ echo $?
1
$int2 est inférieur ou égal à $int3
$ [ $int2 -le $int3 ]
$ echo $?
0
$int2 est inférieur à $int3
$ [ $int2 -lt $int3 ]
$ echo $?
0
$int2 est inférieur ou égal à $int4
$ [ $int2 -le $int4 ]
$ echo $?
0
$int2 est différent de $int3
$ [ $int2 -ne $int3 ]
$ echo $?
0
$int2 n'est pas différent de $int4
$ [ $int2 -ne $int4 ]
$ echo $?
1
$
Opérateur | Signification |
---|---|
! | Négation |
-a | ET |
-o | OU |
Les opérateurs sont exécutés avec une priorité bien précise :
Le fichier /etc/group n'est pas un répertoire
$ [ ! -d /etc/group ]
$ echo $?
0
$
Le fichier monPremierScript.sh existe et est exécutable
$ [ -f monPremierScript.sh -a -x monPremierScript.sh ]
$ echo $?
0
$
Le fichier monPremierScript.sh n'est pas un répertoire mais il est exécutable
$ [ -d monPremierScript.sh -o -x monPremierScript.sh ]
$ echo $?
0
$
Il est possible de modifier la priorité d'exécution des opérateurs en utilisant des paranthèses.
\(........\)
Les parenthèses doivent être protégées par des antislashes afin de ne pas être interprétées par le shell comme étant un regroupement de commandes.
L'utilisateur doit avoir le droit d'écriture sur le fichier fic1 et le fichier fic4 ou fic7 doit exister
$ ls
fic1 fic2 fic3 fic4 fic5 fic6 script.sh
$ [ -w fic1 -a \( -e fic4 -o -e fic7 \) ]
$ echo $?
0
$
Il doit toujours y avoir un espace autour des opérateurs !, -a et -o.
Utilisation de la commande test avec la structure de controle if.
Principe d'utilisation :
if commande1
then
commande2
commande3
...
else
commande4
...
fi
if
commande2
commande3
...
else
commande4
...
fi
La commande1 est exécutée, si son code retour ($?) vaut 0 (vrai) alors les commandes 2 & 3 sont exécutées, sinon c'est la commande4 qui est exécutée (code retour de la commande1 supérieur à 0 - faux).
Exemple :
Dans l'exemple suivant, le script test s'il reçoit bien au minimum 2 arguments.
Dans le cas contraire, le script affiche un message indiquant que le nombre d'arguments est incorrect et se termine en retournant un code erreur 1.
$ nl monTroisiemeScript.sh
1 #! /bin/bash
2 # Ce script doit recevoir en premier argument le nom d'un dossier puis des noms de fichiers pour les suivants
4 # Ce script doit recevoir au minimum 2 arguments
5 # Le premier étant le nom d'un dossier
6 # Les suivants étant les noms des fichiers
7 # On test si il y a 2 arguments au minimum et on retourne le code erreur 1 si c'est faux
8 if [ $# -lt 2 ]
9 then
10 echo "Nombre d'arguments incorrect !!!"
11 exit 1
12 fi
13 # On sauvegarde le premier argument dans la variable rep
14 rep=$1
15 # On décale tous les arguments avec la commande shift
16 shift
17 # Création du répertoire
18 mkdir $rep
19 # On se positionne dans le nouveau répertoire
20 cd $rep
21 # Création des fichiers dans le nouveau répertoire
22 for fichier in $*
23 do
24 touch $fichier
25 done
26 exit 0
$ ./monTroisiemeScript.sh test
Nombre d'arguments incorrect !!!
$ echo $?
1
$
$ ./monTroisiemeScript.sh test3 coucou
$ echo $?
0
$
La commande [[ ]] est une version améliorée de la commande test.
Tous les opérateurs utilisés avec la commandes test restent valables à l'exception des opérateurs logiques -a et -o respectivement remplacés par && et ||.
Contrairement à la commande test, il n'est plus nécessaire d'entourer les variables avec des guillemets.
Les différentes syntaxes utilisables :
$ echo $null
$ test -z "$null"
$ echo $?
0
$ [ -z "$null" ]
$ echo $?
0
$ [[ -z $null ]]
$ echo $?
0
$ [[ -z "$null" ]]
$ echo $?
0
$ [[ $null = "" ]]
$ echo $?
0
$
Les opérateurs suivants ont été ajoutés :
Opérateurs | Code de retour |
---|---|
$chaine = modele | Vrai si $chaine correspond au modèle |
$chaine != modele | Vrai si $chaine ne correspond pas au modèle |
$chaine1 < $chaine2 | Vrai si $chaine1 est lexicographiquement avant $chaine2 |
$chaine1 > $chaine2 | Vrai si $chaine1 est lexicographiquement après $chaine2 |
En utilisant les expressions, il est possible de comparer des chaines à des modèles identiques à celles permettant le remplacement des noms de fichiers.
Caractères spéciaux pour modèles de chaines de caractères | Signification |
---|---|
Caractères spéciaux valables dans tous les shells : | |
* | 0 à n caractères |
? | 1 caractère quelconque |
[abc] | 1 caractère parmis ceux inscrits entre les crochets |
[!abc] | 1 caractère ne faisant pas partie de ceux inscrits entre les crochets |
Caractères spéciaux non valides en Bourne Shell. En bash, il faut activer l'option extglob (shopt -s extglob) |
|
?(expression) | de 0 à 1 fois l'expression |
*(expression) | de 0 à n fois l'expression |
+(expression) | de 1 à n fois l'expression |
@(expression) | 1 fois l'expression |
!(expression) | 0 fois l'expression |
?(expression1 | expression2 | ...) *(expression1 | expression2 | ...) +(expression1 | expression2 | ...) @(expression1 | expression2 |...) !(expression1 | expression2 | ...) |
alternatives |
Exemple :
Le script suivant test si le numéro de téléphone saisi correspond bien au format +33240346523 ou 0240346523
$ nl test_telephone.sh
1 #! /bin/bash
2 echo -e "Saisir un numéro de téléphone : \c"
3 read telephone
4 # Test si le téléphone saisi est de la forme
5 # +33240346523 ou 0240346523
6 if [[ $telephone = @(+33)@([1-9])@([0-9])@([0-9])@([0-9])@([0-9])@([0-9])@([0-9])@([0-9])@([0-9]) ||
7 $telephone = @(0)@([0-9])@([0-9])@([0-9])@([0-9])@([0-9])@([0-9])@([0-9])@([0-9])@([0-9]) ]]
8 then
9 echo "Le numéro est correct"
10 exit 0
11 else
12 echo "Le numéro est incorrect"
13 exit 1
14 fi
$ ./test_telephone.sh
Saisir un numéro de téléphone : 0240020202
Le numéro est correct
$ ./test_telephone.sh
Saisir un numéro de téléphone : +33256985478
Le numéro est correct
$ ./test_telephone.sh
Saisir un numéro de téléphone : 2356958457
Le numéro est incorrect
$ ./test_telephone.sh
Saisir un numéro de téléphone : +33025146987
Le numéro est incorrect
$ ./test_telephone.sh
Saisir un numéro de téléphone : g52365
Le numéro est incorrect
$
Rappels :
Commande test ( [ ] ) | Commande [[ ]] | Signification |
---|---|---|
\(.....\) | (.....) | Regroupement d'expressions |
! | ! | Négation |
-a | && | ET logique |
-o | || | OU logique |
Exemple avec la commande test :
if [ -w $fic1 -a \( -e $rep1 -o -e $rep2 \) ]
then
.....
Exemple avec la commande [[ ]] :
if [[ -w $fic1 && ( -e $rep1 || -e $rep2 ) ]]
then
.....
Ces opérateurs permettent d'exécuter ou non une commande en fonction du code de retour d'une autre commande.
Opérateur | Signification |
---|---|
&& | ET logique |
|| | OU logique |
Syntaxe :
commande1 && commande2
La seconde commande (commande2) est exécutée uniquement si le code de retour de la commande (commande1) est égale à 0 (vrai).
Le code de retour global est égal à 0 (vrai) si le code de retour de chaque commande est égal à 0 (vrai).
Exemple :
Le répertoire temp/temp2 n'existe pas donc la commande cd n'est pas exécutée
$ ls -d temp/temp2
ls: impossible d'accéder à temp/temp2: Aucun fichier ou dossier de ce type
$ pwd
/home/toto
$ [[ -d temp/temp2 ]] && cd temp/temp2
$ echo $? # code de retour de la commande [[ ]]
1
$ pwd
/home/toto
$
Le répertoire temp/temp2 existe donc la commande cd est exécutée
$ mkdir temp/temp2
$ pwd
/home/toto
$ [[ -d temp/temp2 ]] && cd temp/temp2
$ echo $? # code de retour de la commande globale
0
$ pwd
/home/toto/temp/temp2
$
Le répertoire temp/temp2 existe mais le répertoire temp/temp3 n'existe pas donc la commande cd retourne un code erreur égal à 1
$ [[ -d temp/temp2 ]] && cd temp/temp3
-bash: cd: temp/temp3: Aucun fichier ou dossier de ce type
$ echo $? # code de retour de la commande cd
1
$
Ces actions peuvent également être exécutées avec la structure de commande if
$ pwd
/home/toto
$ ls -d temp/temp2
temp/temp2
$ if [[ -d temp/temp2 ]]
> then
> cd temp/temp2
> fi
$ echo $?
0
$ pwd
/home/toto/temp/temp2
$
Syntaxe :
commande1 || commande2
La seconde commande (commande2) est exécutée uniquement si le code de retour de la commande (commande1) est égale à 1 (faux).
Le code de retour global est égal à 0 (vrai) si au moins une des commandes retourne un code égal à 0 (vrai).
Exemple :
Le répertoire temp/temp2 n'existe pas donc la commande echo est exécutée
$ ls -d temp/temp2
ls: impossible d'accéder à temp/temp2: Aucun fichier ou dossier de ce type
$ [[ -d temp/temp2 ]] || echo "Le répertoire n'existe pas"
Le répertoire n'existe pas
$ echo $?
0
$
Le répertoire temp/temp2 existe donc la commande echo n'est pas exécutée
$ mkdir temp/temp2
$ ls -d temp/temp2
temp/temp2
$ [[ -d temp/temp2 ]] || echo "Le répertoire n'existe pas"
$ echo $?
0
$
Ces actions peuvent également être exécutées avec la structure de commande if
$ ls -d temp/temp2
ls: impossible d'accéder à temp/temp2: Aucun fichier ou dossier de ce type
$ if [[ ! -d temp/temp2 ]]
> then
> echo "Le répertoire n'existe pas"
> fi
Le répertoire n'existe pas
$
Ne pas confondre les opérateurs du shell && et || qui effectuent une opération logique entre deux commandes et les opérateurs && et || de la commande [[ ]] qui sont internes à celle-ci
Syntaxe :
expr $nbr1 opérateur $nbr2
expr $chaine : expression régulière
Opérateurs :
Attention, certains opérateurs ayant une signification particulière pour le shell, ceux ci doivent être protégés par un antislash.
Opérateurs | Signification |
---|---|
Opérateurs arithmétiques | |
$nb1 + $nb2 | Addition |
$nb1 - $nb2 | Soustraction |
$nb1 \* $nb2 | Multiplication |
$nb1 / $nb2 | Division |
$nb1 % $nb2 | Modulo |
Opérateurs de comparaison | |
$nb1 \> $nb2 | VRAI si $nb1 est strictement supérieur à $nb2 |
$nb1 \>= $nb2 | VRAI si $nb1 est supérieur ou égal à $nb2 |
$nb1 \< $nb2 | VRAI si $nb1 est strictement inférieur à $nb2 |
$nb1 \<= $nb2 | VRAI si $nb1 est inférieur ou égal à $nb2 |
$nb1 = $nb2 | VRAI si $nb1 est égal à $nb2 |
$nb1 != $nb2 | VRAI si $nb1 est diférent de $nb2 |
Opérateurs logiques | |
$chaine1 \& $chaine2 | VRAI si les 2 chaines sont vraies |
$chaine1 \| $chaine2 | VRAI si l'une des 2 chaines est vraie |
Opérateurs divers | |
-$nb1 | Opposé de $nb1 |
\( expression \) | Regroupement |
$chaine : expression_reguliere | Compare la chaine avec l'expression régulière |
Les arguments de la commande expr doivent toujours être séparés par au moins un espace ou une tabulation.
Exemple :
$ nb=3
$ expr $nb + 5
8
$ expr $nb \* 6
18
$ expr $nb / 2
1
$ nb=10
$ expr $nb % 3
1
$ expr $nb - -5
15
$
Récupérer le résultat dans une variable :
$ nb2=`expr $nb - 2`
$ echo $nb2
8
$
Priorité d'exécution des opérateurs :
$ nb=5
$ nb2=`expr $nb \* 3 + 4`
$ echo $nb2
19
$ nb2=`expr $nb \* \( 3 + 4 \)`
$ echo $nb2
35
$
Résultat d'une comparaison VS valeur du code de retour :
$ nb=2
$ expr $nb \>= 1
1 # Résultat de la comparaison
$ echo $?
0 # Résultat du code de retour
$ expr $nb \>= 3
0 # Résultat de la comparaison
$ echo $?
1 # Résultat du code de retour
$
Différents types de comparaison :
$ nl comparaison.sh
1 #!/bin/bash
2 # Test sur le nombre d'arguments
3 if [[ $# -ne 2 ]]
4 then
5 echo "Mauvais nombre d'arguments"
6 echo "Utilisation : $0 expr1 expr2"
7 exit 1
8 fi
9 # On compare expr1 et expr2 avec la commande EXPR et redirection du résultat dans /dev/null
10 if expr $1 \> $2 > /dev/null
11 then
12 echo "Comparaison EXPR : $1 est supérieur à $2"
13 else
14 echo "Comparaison EXPR : $1 est inférieur à $2"
15 fi
16 # On compare expr1 et expr2 avec la commande [[ ]] (lexicographiquement)
17 if [[ $1 > $2 ]]
18 then
19 echo "Comparaison lexico.. [[ ]] : $1 est supérieur à $2"
20 else
21 echo "Comparaison lexico.. [[ ]] : $1 est inférieur à $2"
22 fi
23 # On compare expr1 et expr2 avec la commande [[ ]]
24 if [[ $1 -gt $2 ]]
25 then
26 echo "Comparaison [[ ]] : $1 est supérieur à $2"
27 else
28 echo "Comparaison [[ ]] : $1 est inférieur à $2"
29 fi
30 exit 0
$ ./comparaison.sh 9 5
Comparaison EXPR : 9 est supérieur à 5
Comparaison lexico.. [[ ]] : 9 est supérieur à 5
Comparaison [[ ]] : 9 est supérieur à 5
$ ./comparaison.sh 50 9
Comparaison EXPR : 50 est supérieur à 9
Comparaison lexico.. [[ ]] : 50 est inférieur à 9
Comparaison [[ ]] : 50 est supérieur à 9
$ ./comparaison.sh a b
Comparaison EXPR : a est inférieur à b
Comparaison lexico.. [[ ]] : a est inférieur à b
Comparaison [[ ]] : a est inférieur à b
$ ./comparaison.sh t r
Comparaison EXPR : t est supérieur à r
Comparaison lexico.. [[ ]] : t est supérieur à r
Comparaison [[ ]] : t est inférieur à r
$
Le résultat de la commande EXPR est toujours exact que ce soit des chiffres ou des caractères.
Syntaxe :
((expression_arithmétique))
Utilisation :
La commande (( )) dispose de nombreux avantages par rapport à la commande expr
Une grande partie des opérateurs proviennent du langage C
Opérateurs | Signification |
---|---|
Opérateurs arithmétiques | |
nbr1 + nbr2 | Addition |
nbr1 - nbr2 | Soustraction |
nbr1 * nbr2 | Multiplication |
nbr1 / nbr2 | Division |
nbr1 % nbr2 | Modulo |
Opérateurs travaillant sur les bits | |
~nbr1 | Complément à 1 |
nbr1 >> nbr2 | Décalage sur nbr1 de nbr2 bits à droite |
nbr1 << nbr2 | Décalage sur nbr1 de nbr2 bits à gauche |
nbr1 & nbr2 | ET bit à bit |
nbr1 | nbr2 | OU bit à bit |
nbr1 ^ nbr2 | OU exclusif bit à bit |
Opérateurs de comparaison | |
nbr1 > nbr2 | VRAI si nbr1 est strictement supérieur à nbr2 |
nbr1 >= nbr2 | VRAI si nbr1 est supérieur ou égal à nbr2 |
nbr1 < nbr2 | VRAI si nbr1 est strictement inférieur à nbr2 |
nbr1 <= nbr2 | VRAI si nbr1 est inférieur ou égal à nbr2 |
nbr1 == nbr2 | VRAI si nbr1 est égal à nbr2 |
nbr1 != nbr2 | VRAI si nbr1 est différent de nbr2 |
Opérateurs logiques | |
!nbr1 | Inverse la valeur de vérité de nbr1 |
&& | ET |
|| | OU |
Opérateurs divers | |
-nbr1 | Opposé de nbr1 |
nbr1 = expression | Assignement |
(expression) | Regroupement |
nbr1 binop= nbr2 | binop représente l'un des opérateurs suivants : +, -, /, *, %, >>, <<, &, |, ^. Equivalent à nbr1 = nbr1 binop nbr2 |
Exemples :
Ajouter 10 à nbr1 (2 méthodes différentes)
$ nbr1=10
$ ((nbr1=nbr1+10))
$ echo $nbr1
20
$ nbr1=10
$ ((nbr1+=10))
$ echo $nbr1
20
$
Test si nbr1 est supérieur à nbr2 et inversement
$ nbr1=5
$ nbr2=6
$ ((nbr1>nbr2))
$ echo $?
1 # Code retour 1 (faux) car nbr1 n'est pas supérieur à nbr2
$ ((nbr1<nbr2))
$ echo $?
0 # Code retour 0 (vrai) car nbr1 est inférieur à nbr2
$
Le script suivant compare les 2 arguments passés en paramètre
$ nl comparaison2.sh
1 #!/bin/bash
2 # Test sur le nombre d'arguments
3 if (($#!=2))
4 then
5 echo "Mauvais nombre d'arguments"
6 echo "Utilisation : $0 nbr1 nbr2"
7 exit 1
8 fi
9 # On compare nbr1 et nbr2 avec la commande (( ))
10 if (($1<$2))
11 then
12 echo "$1 est inférieur à $2"
13 else
14 if (($1>$2))
15 then
16 echo "$1 est supérieur à $2"
17 else
18 if (($1==$2))
19 then
20 echo "$1 est égal à $2"
21 else
22 echo "Comparaison impossible"
23 fi
24 fi
25 fi
26 exit 0
$ ./comparaison2.sh 2 8
2 est inférieur à 8
$ ./comparaison2.sh 8 2
8 est supérieur à 2
$ ./comparaison2.sh 8 8
8 est égal à 8
$
Regroupements et tests logiques
$ nbr1=2
$ nbr2=5
$ if (( (nbr1>0) && (nbr2>nbr1) ))
> then
> echo "nbr1 est supérieur à 0 et inférieur à nbr2"
> else
> echo "nbr1 est égal à 0 ou supérieur à nbr2"
> fi
nbr1 est supérieur à 0 et inférieur à nbr2
$
La commande let est équivalente à ((expression))
Syntaxe :
let "expression"
Exemple :
Multiplier nbr1 par 3
$ nbr1=5
$ let "nbr1=nbr1*3"
$ echo $nbr1
15
$
Calculer le modulo de nbr1 par 2 et l'affecter à la variable nbr2
$ nbr1=5
$ let "nbr2=nbr1%2"
$ echo $nbr1
5
$ echo $nbr2
1
$
Il existe les caractères de substitution de commandes mais il existe également les caractères de substitution d'expressions arithmétiques.
Syntaxe :
commande argument1 $((expression_arithmetique)) ... argumentn
Exemple :
Rappel sur la substitution de commandes
$ echo "Nombre de users connectes : `who | wc -l`"
Nombre de users connectes : 1
ou
$ echo "Nombre de users connectes : $(who | wc -l)"
Nombre de users connectes : 1
Substitution d'expressions arithmétiques
$ cpt=1
$ ((cpt+=1)) # Le résultat de la commande n'est pas affichée
$ echo $cpt
2
$
$ cpt=1
$ echo "Nouveau compteur : `((cpt+=1))`"
Nouveau compteur : # Le résultat de la commande n'est pas affichée et le compteur n'est pas incrémenté
$ echo $cpt
1
$
$ cpt=1
$ echo "Nouveau compteur : $((cpt+=1))"
Nouveau compteur : 2 # Le résultat de la commande est affiché et le compteur est incrémenté
$ echo $cpt
2
$
Il ne faut pas confondre (( )) et $(( )).
(( )) est une commande interne au shell.
$(( )) sont des caractères spéciaux du shell à l'égal de `` ou $().
Le shell propose quelques options qui permettent de débugger des scripts shell.
L'option -x permet de débugger un script shell en affichant l'exécution des commandes après traitement des caractères spéciaux du shell.
Les différentes syntaxes permettant d'activer l'option -x :
Activer l'option
Désactiver l'option
Exemple :
Dans l'exemple suivant, la variable fichier n'a pas été préfixée par le symbole $.
$ nl liste.sh
1 #!/bin/bash
2 for fichier in `ls`
3 do
4 if [[ -f fichier ]]
5 then
6 echo "$fichier"
7 fi
8 done
$
L'exécution du script ne retourne aucun résultat malgré la présence de fichiers dans le dossier d'exécution du script.
$ ./liste.sh
$
L'exécution du script avec activation de l'option -x démontre effectivement que la variable fichier n'est pas remplacée par sa valeur.
$ bash -x liste.sh
++ ls
+ for fichier in '`ls`'
+ [[ -f fichier ]]
+ for fichier in '`ls`'
+ [[ -f fichier ]]
+ for fichier in '`ls`'
+ [[ -f fichier ]]
...
$
L'activation de l'option de débuggage peut également être lancée directement dans le script.
$ nl liste.sh
1 #!/bin/bash
2 set -x
3 for fichier in `ls`
4 do
5 if [[ -f fichier ]]
6 then
7 echo "$fichier"
8 fi
9 done
$
Après correction de l'erreur et exécution du script en mode débuggage.
$ nl liste.sh
1 #!/bin/bash
2 set -x
3 for fichier in `ls`
4 do
5 if [[ -f "$fichier" ]]
6 then
7 echo "$fichier"
8 fi
9 done
$ ./liste.sh
++ ls
+ for fichier in '`ls`'
+ [[ -f 1coucou ]]
+ echo 1coucou
1coucou
+ for fichier in '`ls`'
+ [[ -f 24902 ]]
+ for fichier in '`ls`'
+ [[ -f 25013 ]]
+ for fichier in '`ls`'
+ [[ -f 25031 ]]
+ for fichier in '`ls`'
+ [[ -f 25043 ]]
+ for fichier in '`ls`'
+ [[ -f comparaison2.sh ]]
+ echo comparaison2.sh
comparaison2.sh
...
$
Fonction | Bourne shell, ksh, bash | ksh, bash |
---|---|---|
Lecture des commandes sans exécution et détection des erreurs de syntaxe. | set -n set +n |
set -o noexec set +o noexec |
Affichage des commandes avant substitution des caractères spéciaux du shell | set -v set +v |
set -o verbose set +o verbose |
Exemple :
Dans l'exemple suivant, un guillemet a été volontairement omis.
$ nl liste.sh
1 #!/bin/bash
2 set -n
3 for fichier in `ls`
4 do
5 if [[ -f "$fichier ]]
6 then
7 echo "$fichier"
8 fi
9 done
$ ./liste.sh
./liste.sh: line 7: Caractère de fin de fichier (EOF) prématuré lors de la recherche du « " » correspondant
./liste.sh: line 10: argument inattendu pour l'opérateur conditionnel à un argument
./liste.sh: line 10: Erreur de syntaxe : fin de fichier prématurée
$
$ nl liste.sh
1 #!/bin/bash
2 set -v
3 for fichier in `ls`
4 do
5 if [[ -f "$fichier ]]
6 then
7 echo "$fichier"
8 fi
9 done
$ ./liste.sh
for fichier in `ls`
do
if [[ -f "$fichier ]]
then
echo "$fichier"
fi
done
./liste.sh: line 7: Caractère de fin de fichier (EOF) prématuré lors de la recherche du « " » correspondant
./liste.sh: line 10: argument inattendu pour l'opérateur conditionnel à un argument
./liste.sh: line 10: Erreur de syntaxe : fin de fichier prématurée
$
La structure de controle if permet de réaliser des tests.
La commande située à droite du if est exécutée.
Si le code retour de la commande ($?) est égal à 0 (vrai), les commandes situées dans le bloc then sont exécutées.
Si le code de retour est supérieur à 0 (faux), ce sont les commandes situées dans le bloc else (optionnel) qui sont exécutées.
Dans le cas où le bloc else n'est pas spécifié, le shell continue à la première commande située sous le fi.
Les différentes syntaxes :
if, then, else, fi
if commande1
then
commande2
commande3
...
else
commande4
...
fi
if, then, fi
if commande1
then
commande2
commande3
...
fi
if, then, elif, else, fi
if commande1
then
commande2
commande3
...
elif commande4
then
commande5
...
else
commande6
...
fi
Le mot clé fi permet de fermer la structure de controle if.
Le mot clé elif n'a pas de fermeture.
Autres syntaxes :
Le mot clé then peut être placé sur la même ligne que le if à condition de les séparer à l'aide d'un point virgule.
if commande1 ; then
commande2
commande3
...
fi
Plusieurs structures de controles if peuvent être imbriquées les unes dans les autres.
if commande1
then
commande2
...
else
if commande3
then
commande4
...
else
commande5
...
fi
fi
Exemple :
Le script suivant vérifie si un argument est passé en paramètre et dans le cas contraire demande une saisie clavier à l'utilisateur.
Le script vérifie ensuite que le user saisi existe bien dans le fichier /etc/passwd.
$ nl user_passwd.sh
1 #!/bin/bash
2 if [[ $# -ne 1 ]]
3 then
4 echo -e "Saisir le nom d'un user : \c"
5 read user
6 else
7 user=$1
8 fi
9 if grep -q "^$user:" /etc/passwd
10 then
11 echo "Le user $user existe"
12 echo "Son UID est le : $(grep "^$user:" /etc/passwd | cut -d":" -f3)"
13 echo "Son GID est le : $(grep "^$user:" /etc/passwd | cut -d":" -f4)"
14 else
15 echo "Le user $user n'existe pas !!!"
16 fi
17 exit 0
$ ./user_passwd.sh root
Le user root existe
Son UID est le : 0
Son GID est le : 0
$ ./user_passwd.sh
Saisir le nom d'un user : www-data
Le user www-data existe
Son UID est le : 33
Son GID est le : 33
$
La structure de controle case permet elle aussi d'effectuer des tests.
Elle permet d'orienter la suite du programme en fonction d'un choix de différentes valeurs.
Quand il y a un nombre important de choix, la commande case est plus appropriée que la commande if.
Syntaxe :
case $variable in
modele1) commande1
...
;;
modele2) commande2
...
;;
modele3 | modele4 | modele5 ) commande3
...
;;
esac
Le shell compare la valeur de la variable aux différents modèle renseignés.
Lorsque la valeur correspond au modèle, les commandes faisant partie du bloc sont exécutées.
Les caractères ;; permettent de fermer le bloc et de mettre fin au case.
Le shell continue à la première commande située sous esac.
Il ne faut surtout pas oublier les caractères ;; car cela engendrera une erreur.
Rappel des caractères spéciaux :
Caractères spéciaux pour modèles de chaines de caractères | Signification |
---|---|
Caractères spéciaux valables dans tous les shells : | |
* | 0 à n caractères |
? | 1 caractère quelconque |
[abc] | 1 caractère parmis ceux inscrits entre les crochets |
[!abc] | 1 caractère ne faisant pas partie de ceux inscrits entre les crochets |
Caractères spéciaux non valides en Bourne Shell. En bash, il faut activer l'option extglob (shopt -s extglob) |
|
?(expression) | de 0 à 1 fois l'expression |
*(expression) | de 0 à n fois l'expression |
+(expression) | de 1 à n fois l'expression |
@(expression) | 1 fois l'expression |
!(expression) | 0 fois l'expression |
?(expression1 | expression2 | ...) *(expression1 | expression2 | ...) +(expression1 | expression2 | ...) @(expression1 | expression2 |...) !(expression1 | expression2 | ...) |
alternatives |
Exemple :
Le script suivant permet de créer, modifier, visualiser et supprimer un fichier dans le répertoire d'exécution du script.
Il prend en argument un nom de fichier et affiche un menu.
Utilisation de case avec imbrication de if.
$ nl file.sh
1 #!/bin/bash
2 #set -x
3 # Si le nombre d'arguments est different de 1 on quitte avec code 1
4 if [[ $# -ne 1 ]]
5 then
6 echo "Nombre d'arguments incorrect"
7 echo "Usage : $0 file"
8 exit 1
9 fi
10 # On affiche le menu
11 echo -e "1(Creer) "
12 echo -e "2(Editer) "
13 echo -e "3(Afficher) "
14 echo -e "4(Supprimer)"
15 echo -e "Votre choix : \c"
16 # On recupere la valeur saisi
17 read choix
18 # Si la valeur saisi est differente de 1, 2, 3 ou 4 on quitte avec code 1
19 if [[ "$choix" != [1-4] ]]
20 then
21 echo "Choix incorrect"
22 exit 1
23 fi
24 # En fonction de la valeur saisi on execute les differentes actions
25 case "$choix" in
26 # Si choix = 1 --> creation
27 1) if [[ -e "$1" ]]
28 then
29 if [[ -f "$1" ]]
30 then
31 echo "Fichier $1 deja existant"
32 elif [[ -d "$1" ]]
33 then
34 echo "$1 est un repertoire"
35 fi
36 exit 1
37 else
38 touch "$1"
39 nano "$1"
40 fi
41 ;;
42 # Si choix = 2 --> edition
43 2) if [[ -f "$1" ]]
44 then
45 nano "$1"
46 else
47 if [[ -d "$1" ]]
48 then
49 echo "$1 est un repertoire et ne peut etre edite"
50 else
51 echo "Fichier $1 inexistant"
52 fi
53 exit 1
54 fi
55 ;;
56 # Si choix = 3 --> affichage
57 3) if [[ -f "$1" ]]
58 then
59 more "$1"
60 else
61 if [[ -d "$1" ]]
62 then
63 echo "$1 est un repertoire et ne peut etre visualise"
64 else
65 echo "Fichier $1 inexistant"
66 fi
67 exit 1
68 fi
69 ;;
70 # Si choix = 4 --> suppression
71 4) if [[ -f "$1" ]]
72 then
73 rm "$1"
74 else
75 if [[ -d "$1" ]]
76 then
77 echo "$1 est un repertoire et ne peut etre supprime"
78 else
79 echo "Fichier $1 inexistant"
80 fi
81 exit 1
82 fi
83 ;;
84 # Fin du case
85 esac
86 # Tout c'est bien deroule on quitte avec le code 0
87 exit 0
$ ./file.sh test4
1(Creer)
2(Editer)
3(Afficher)
4(Supprimer)
Votre choix : 1
$
Syntaxe :
La boucle for permet de traiter une liste de valeurs indiquée à droite du mot clé in.
A chaque tour de boucle, la variable var est initialisée avec une des valeurs de la liste.
Elles sont traitées dans l'ordre de leur énumération.
Liste de valeurs citée directement
for var in valeur1 valeur2 valeur3 ... valeurn
do
commande
done
Liste de valeurs contenue dans une variable
for var in $variable
do
commande
done
Liste de valeurs générée par substitution de commande
for var in `commande`
do
commande
done
Liste de valeurs générée par substitution de caractères de génération de noms de fichiers
for var in *.ext
do
commande
done
Liste par défaut : Arguments de la ligne de commande
for var
do
commande
done
for var in $*
do
commande
done
Avec incrémentation d'une variable
for (( var=valeurMin; var<=valeurMax; var++ ))
do
commande
done
Exemple :
Un script compte à rebours
$ nl boucleFor01.sh
1 #!/bin/bash
2 for var in 10 9 8 7 6 5 4 3 2 1 0
3 do
4 echo "$var"
5 done
6 exit 0
$ ./boucleFor01.sh
10
9
8
7
6
5
...
$
Lister les fichiers d'un ou plusieurs dossiers
$ nl boucleFor02.sh
1 #!/bin/bash
2 if [[ $# -lt 1 ]]
3 then
4 echo "Nombre d'argument incorrect"
5 echo "Utilisation $0 dossier1 dossier2 dossiern"
6 exit 1
7 fi
8 for dossier in $*
9 do
10 if [[ -d $dossier ]]
11 then
12 echo "Liste des fichiers du dossier $dossier"
13 for fichier in `ls $dossier`
14 do
15 echo "$fichier"
16 done
17 fi
18 done
19 exit 0
$ ./boucleFor02.sh coucou 24902 25013 25031
Liste des fichiers du dossier coucou
test
Liste des fichiers du dossier 24902
fichier_0
fichier_1
fichier_2
fichier_3
Liste des fichiers du dossier 25013
fichier_0
fichier_1
fichier_2
Liste des fichiers du dossier 25031
fichier_0
fichier_1
fichier_2
fichier_3
$
En utilisant une variable incrémentée :
$ for (( i=0; i <= 10; i++ )); do echo $i; done
0
1
2
3
4
5
6
7
8
9
10
$
Idem avec la syntaxe suivante :
$ for i in {0..10}; do echo $i; done
0
1
2
3
4
5
6
7
8
9
10
$
Syntaxe :
while commande1
do
commande2
...
done
La boucle while permet d'exécuter les commandes présentes entre le do et le done tant que la commande1 placée à droite du while retourne un code vrai.
Exemple :
Le script suivant demande de saisir 53 et continue tant que c'est faux
$ nl boucleWhile01.sh
1 #!/bin/bash
2 nbr=0
3 while ((nbr!=53))
4 do
5 echo -e "Saisir 53 : \c"
6 read nbr
7
8 done
9 exit 0
$ ./boucleWhile01.sh
Saisir 53 : rt
Saisir 53 : 54
Saisir 53 : R4
Saisir 53 : 53
$
Le script suivant affiche le compteur tant qu'il est inférieur à 10
$ nl boucleWhile02.sh
1 #!/bin/bash
2 cpt=0
3 while ((cpt<10))
4 do
5 echo "Le compteur vaut : $cpt"
6 ((cpt+=1))
7 done
8 exit 0
$ ./boucleWhile02.sh
Le compteur vaut : 0
Le compteur vaut : 1
Le compteur vaut : 2
Le compteur vaut : 3
Le compteur vaut : 4
Le compteur vaut : 5
Le compteur vaut : 6
Le compteur vaut : 7
Le compteur vaut : 8
Le compteur vaut : 9
$
Le script suivant effectue une somme des nombres saisis
$ nl boucleWhile03.sh
1 #!/bin/bash
2 somme=0
3 echo "Saisir un nombre, ^d pour afficher la somme"
4 while read nombre
5 do
6 if [[ $nombre != +([0-9]) ]]
7 then
8 echo "$nombre n'est pas un nombre"
9 continue
10 fi
11 ((somme+=nombre))
12 done
13 echo "La somme est de : $somme"
14 exit 0
$ ./boucleWhile03.sh
Saisir un nombre, ^d pour afficher la somme
56
32
89
9.6
9.6 n'est pas un nombre
g8
g8 n'est pas un nombre
54
La somme est de : 231
$
Le mot clé continue permet de remonter aussitôt à la boucle while sans exécuter la commande suivante
Attention aux boucles infinies
Ce script provoqe une boucle infinie car il manque l'incrémentation du compteur
$ nl boucleWhile04.sh
1 #!/bin/bash
2 cpt=0
3 while ((cpt<10))
4 do
5 echo "Le compteur vaut : $cpt"
6 done
7 exit 0
$
Le shell propose également la commande interne : qui renvoie toujours vrai et permet donc de faire une boucle infinie avec un while.
$ nl boucleWhile05.sh
1 #!/bin/bash
2 while :
3 do
4 echo "Boucle infinie"
5 done
6 exit 0
$
En bash et ksh, la commande true propose exactement la même chose.
$ nl boucleWhile05.sh
1 #!/bin/bash
2 while true
3 do
4 echo "Boucle infinie"
5 done
6 exit 0
$
Syntaxe :
until commande1
do
commande2
...
done
A l'inverse de while, la commande until exécute les commandes situées entre le do et le done tant que la commande située à droite du until retourne un code faux.
Exemple :
Le script suivant boucle tant que le nombre saisi n'est pas égal à 53
$ nl boucleUntil01.sh
1 #!/bin/bash
2 nbr=0
3 until ((nbr==53))
4 do
5 echo -e "Saisir 53 : \c"
6 read nbr
7 done
8 exit 0
$ ./boucleUntil01.sh
Saisir 53 : 45
Saisir 53 : rt
Saisir 53 : fd
Saisir 53 : 53
$
Le script suivant permet, en tâche de fond, de surveiller un répertoire donné et d'informer l'utilisateur de l'arrivée d'un fichier attendu dans ce répertoire.
Pour plus de sécurité sur l'intégrité du fichier attendu, un fichier témoin devra être créé à la suite du fichier attendu puisque le principal contrôle se fera sur l'existence de ce fichier.
$ nl boucleUntil02.sh
1 #!/bin/bash
2 # Il doit y avoir au minimum 2 paramètres en arguments et un maximum de 3
3 if [[ $# -lt 2 || $# -gt 3 ]]
4 then
5 echo "Utilisation : $0 repertoire fichier [ temoin ]"
6 exit 1
7 fi
8 # Le premier argument doit être un répertoire
9 if [[ ! -d $1 ]]
10 then
11 echo "$1 n'est pas un répertoire"
12 exit 2
13 fi
14 # Nom du fichier témoin par défaut
15 ficTemoin=${3:-temoin}
16 # Exécution de la boucle en attendant l'arrivée du fichier témoin avec une pause toutes les 3 secondes
17 until [[ -e $1/$ficTemoin ]]
18 do
19 sleep 3
20 done
21 # Vérification que le fichier attendu est bien présent
22 if [[ ! -e $1/$2 ]]
23 then
24 echo "Le fichier témoin existe mais le fichier attendu est absent"
25 exit 3
26 fi
27 # Sauvegarde du fichier attendu dans le HOME de l'utilisateur avec horodatage et suppression du fichier témoin
28 date=$(date '+%Y%m%d_%H%M')
29 newFichier=$2.$date
30 mv $1/$2 $HOME/$newFichier
31 rm $1/$ficTemoin
32 # Envoi d'un mail à l'utilisateur
33 mail $LOGNAME <<FIN
34 Le fichier $HOME/$newFichier est bien arrivé.
35 FIN
36 echo "$0 : Vous avez reçu un message !!! "
37 exit 0
$ ./boucleUntil02.sh /tmp monFichier & # Lancement du script en arrière plan grâce à la commande &
[1] 2298
$ touch /tmp/monFichier # Création du fichier attendu
$ touch /tmp/temoin # Création du fichier témoin
$ ./boucleUntil02.sh : Vous avez reçu un message !!! # Message généré par la ligne 36
[1]+ Done ./boucleUntil02.sh /tmp monFichier
$
il ne reste plus qu'à consulter sa boite mail pour lire le message envoyé par le script.
Les commandes break et continue peuvent s'utiliser à l'intérieur des boucles for, while, until et select.
La commande break permet de sortir d'une boucle.
La commande continue permet de remonter à la condition d'une boucle.
Syntaxe :
Quitter la boucle de premier niveau
break
Quitter la boucle de niveau n
break n
Remonter à la condition de la boucle de premier niveau
continue
Remonter à la condition de la boucle de niveau n
continue n
Exemple :
$ nl boucleWhile06.sh
1 #!/bin/bash
2 somme=0
3 while true
4 do
5 echo "Saisir un nombre, ^d pour afficher la somme"
6 if read nombre
7 then
8 if [[ $nombre != +([0-9]) ]]
9 then
10 echo "$nombre n'est pas un nombre"
11 continue
12 fi
13 ((somme+=nombre))
14 else
15 break
16 fi
17 done
18 echo "La somme est de : $somme"
19 exit 0
$ ./boucleWhile06.sh
Saisir un nombre, ^d pour afficher la somme
23
Saisir un nombre, ^d pour afficher la somme
56
Saisir un nombre, ^d pour afficher la somme
54
Saisir un nombre, ^d pour afficher la somme
89
Saisir un nombre, ^d pour afficher la somme
La somme est de : 222
$
Les variables $* et $@ contiennent la liste des arguments d'un script shell.
Lorsqu'elles ne sont pas entourées par des guillemets, elles sont équivalentes.
Exemple :
$ nl scr01.sh
1 #!/bin/bash
2 cpt=1
3 echo "Utilisation de la variable \$*"
4 for arg in $*
5 do
6 echo "Argument $cpt : $arg"
7 ((cpt+=1))
8 done
9 cpt=1
10 echo "Utilisation de la variable \$@"
11 for arg in $@
12 do
13 echo "Argument $cpt : $arg"
14 ((cpt+=1))
15 done
16 exit 0
$ ./scr01.sh a b "c d e" f
Utilisation de la variable $*
Argument 1 : a
Argument 2 : b
Argument 3 : c
Argument 4 : d
Argument 5 : e
Argument 6 : f
Utilisation de la variable $@
Argument 1 : a
Argument 2 : b
Argument 3 : c
Argument 4 : d
Argument 5 : e
Argument 6 : f
$
Interprétation :
Les guillemets autour de $* supprime la signification des espaces contenus dans $*.
Exemple :
$ nl scr02.sh
1 #!/bin/bash
2 cpt=1
3 echo "Utilisation de la variable \"\$*\""
4 for arg in "$*"
5 do
6 echo "Argument $cpt : $arg"
7 ((cpt+=1))
8 done
9 exit 0
$ ./scr02.sh a b c "d e f" g
Utilisation de la variable "$*"
Argument 1 : a b c d e f g
$
Interprétation :
La variable $@ placée entre guillemets permet de conserver la protection des arguments par les guillemets.
Exemple :
$ nl scr03.sh
1 #!/bin/bash
2 cpt=1
3 echo "Utilisation de la variable \"\$@\""
4 for arg in "$@"
5 do
6 echo "Argument $cpt : $arg"
7 ((cpt+=1))
8 done
9 exit 0
$ ./scr03.sh a b c "d e f" g
Utilisation de la variable "$@"
Argument 1 : a
Argument 2 : b
Argument 3 : c
Argument 4 : d e f
Argument 5 : g
$
Interprétation :
Les shells BASH et KSH offrent des fonctionnalités supplémentaires au niveau des substitution de variables.
Syntaxe :
${#variable}
Exemple :
$ variable="Une chaine de texte"
$ echo $variable
Une chaine de texte
$ echo "La chaine contient ${#variable} caractères"
La chaine contient 19 caractères
$
Exemple avec la variable suivante :
$ variable="col1|col2|col3|col4|col5"
$ echo $variable
col1|col2|col3|col4|col5
$
Cette variable est constituée de 5 segments délimités par le caractère |
Le contenu de la variable n'est jamais modifié
Syntaxe :
${variable#modele}
modele est une chaine de caractère incluant les caractères spéciaux *, ?, [ ], ?(expression), +(expression), *(expression), @(expression), !(expression)
Rappel des expressions pour la substitution des noms de fichiers
Le caractère # signifie "Chaine la plus courte possible en partant de la gauche"
Exemple :
$ echo ${variable#*|}
col2|col3|col4|col5
$
Syntaxe :
${variable##modele}
Les caractères ## signifient "Chaine la plus longue possible en partant de la gauche"
Exemple :
$ echo ${variable##*|}
col5
$
Syntaxe :
${variable%modele}
Le caractère % signifie "Chaine la plus courte possible en partant de la droite"
Exemple :
$ echo ${variable%|*}
col1|col2|col3|col4
$
Syntaxe :
${variable%%modele}
Les caractères %% signifient "Chaine la plus longue possible en partant de la droite"
Exemple :
$ echo ${variable%%|*}
col1
$
En bash, ne pas oublier d'activer l'option extglob avec la commande shopt -s extglob afin de permettre au shell d'interpréter les modèles utilisant les expressions complexes.
Avec les shells récents, il est possible d'utiliser des tableaux à 1 dimension.
Les éléments du tableau commencent toujours à l'indice 0.
Syntaxe :
tableau[indice]=valeur
Exemple :
$ tableau[0]=15
$ tableau[3]=20
$
Les indices non initialisés sont vides.
Syntaxe :
${tableau[indice]}
Exemple :
$ echo ${tableau[3]}
20
$ echo ${tableau[0]}
15
$ echo ${tableau[2]}
$
L'indice 2 du tableau est vide.
Syntaxe :
tableau=(valeur1 valeur2 valeur3 ..... valeurn)
Exemple :
$ tableau=(02 40 35 68 98 45 52 03)
$ echo ${tableau[0]}
02
$ echo ${tableau[2]}
35
$
Toutes les précédentes valeurs contenues dans le tableaux sont effacées.
Syntaxe :
${tableau[*]}
Exemple :
$ echo ${tableau[*]}
02 40 35 68 98 45 52 03
$
Syntaxe :
${#tableau[*]}
Exemple :
$ echo ${#tableau[*]}
8
$
Syntaxe :
${#tableau[indice]}
Exemple :
$ echo ${#tableau[0]}
2
$
$ tab=("un" "deux" "trois")
$ for m in ${tab[@]}; do echo $m; done
un
deux
trois
$
La commande set utilisée sans option mais suivie d'arguments affecte ces derniers aux paramètres positionnels $1, $2, $3 ....., $*, $@ et $#.
Cela permet de manipuler plus facilement le résultat de diverses substitutions.
Exemple :
$ ls
fichier_0 fichier_2 fichier_4 fichier_6 fichier_8
fichier_1 fichier_3 fichier_5 fichier_7 fichier_9
$ set `ls`
$
La liste des fichiers obtenue avec la commande ls est maintenant affecté aux paramètres positionnels.
$ echo $#
10
$ echo $*
fichier_0 fichier_1 fichier_2 fichier_3 fichier_4 fichier_5 fichier_6 fichier_7 fichier_8 fichier_9
$ echo $1
fichier_0
$ echo $3
fichier_2
$ echo $9
fichier_8
$ echo ${10}
fichier_9
$
Les fonctions permettent de regrouper et d'exécuter des commandes à différents endroits d'un script.
Cela permet de créer des fonctions personnalisées réutilisables.
Une fonction doit être définie au début d'un script, avant sa première utilisation.
Il existe 2 syntaxes permettant de définir une fonction.
Première syntaxe :
Ce sont les doubles parenthèses ( ) qui indique au shell la définition d'une fonction
Définition d'une fonction
maFonction () {
commande1
commande2
.....
}
Appel d'une fonction
maFonction
Seconde syntaxe :
Le mot clé function remplace les doubles parenthèses ( )
Définition d'une fonction
function maFonction {
commande1
commande2
.....
}
Appel d'une fonction
maFonction
Une fonction peut être appelée aussi bien à partir du programme principal qu'à partir d'une autre fonction.
Exemple :
$ nl fonction01.sh
1 #!/bin/bash
2 fctn01 () {
3 echo "Fonction fctn01"
4 }
5 function fctn02 {
6 echo "Fonction fctn02"
7 }
8 echo "Début du programme principal"
9 echo "Appel de la fonction fctn01"
10 fctn01
11 echo "Appel de la fonction fctn02"
12 fctn02
13 echo "Fin du programme principal"
14 exit 0
$ ./fonction01.sh
Début du programme principal
Appel de la fonction fctn01
Fonction fctn01
Appel de la fonction fctn02
Fonction fctn02
Fin du programme principal
$
Dès qu'une fonction est définie, celle-ci est considérée par le shell comme étant une commande interne.
Comme toutes commandes Linux, une fonction retourne également un code d'erreur.
Si le code erreur n'est pas spécifié, celui retourné par défaut correspond au code erreur de la dernière commande exécutée dans la fonction.
La commande return permet de retourner le code erreur de la fonction concernée. Ce code doit obligatoirement correspondre à un nombre compris entre 0 et 255.
Le code erreur retourné par la fonction est récupérable grâce à la variable $?.
Exemple :
Le script suivant test si l'utilisateur saisi existe sur le système.
$ nl fonction02.sh
1 #!/bin/bash
2 function pause {
3 echo "Appuyer sur Entrée pour continuer"
4 read x
5 }
6 function existUser {
7 echo -e "Saisir le nom d'un utilisateur : \c"
8 read user
9 if grep -q "^$user:" /etc/passwd ; then
10 return 0
11 fi
12 return 1
13 }
14 while true
15 do
16 clear
17 echo "- 1 - Savoir si un utilisateur existe"
18 echo "- 2 - Connaitre l'UID d'un utilisateur"
19 echo "- 3 - Fin"
20 echo -e "Votre choix : \c"
21 read choix
22 case $choix in
23 1) if existUser
24 then
25 echo "L'utilisateur $user existe"
26 else
27 echo "l'utilisateur $user n'existe pas"
28 fi
29 ;;
30 2) echo "Option non disponible"
31 ;;
32 3) exit 0
33 ;;
34 esac
35 pause
36 done
$
Dans un script shell, sans définition particulière, toutes les variables utilisées sont globales à tout le script.
Qu'une variable soit définie au niveau du programme principal ou d'une fonction, elle est accessible n'importe où dans le script.
Par exemple, dans le script fonction02.sh, la variable $user est initialisée dans la fonction existUser (ligne 8) et utilisée également au niveau du programme principal (ligne 25 et 27).
$ nl fonction02.sh
1 #!/bin/bash
2 function pause {
3 echo "Appuyer sur Entrée pour continuer"
4 read x
5 }
6 function existUser {
7 echo -e "Saisir le nom d'un utilisateur : \c"
8 read user
9 if grep -q "^$user:" /etc/passwd ; then
10 return 0
11 fi
12 return 1
13 }
14 while true
15 do
16 clear
17 echo "- 1 - Savoir si un utilisateur existe"
18 echo "- 2 - Connaitre l'UID d'un utilisateur"
19 echo "- 3 - Fin"
20 echo -e "Votre choix : \c"
21 read choix
22 case $choix in
23 1) if existUser
24 then
25 echo "L'utilisateur $user existe"
26 else
27 echo "l'utilisateur $user n'existe pas"
28 fi
29 ;;
30 2) echo "Option non disponible"
31 ;;
32 3) exit 0
33 ;;
34 esac
35 pause
36 done
$
La commande typeset permet de définir des variables locales à une fonction.
Syntaxe :
typeset variable
typeset variable=valeur
Exemple :
$ nl fonction03.sh
1 #!/bin/bash
2 function f1 {
3 # var1 est une variable locale
4 typeset var1
5 echo "Dans la fonction f1 => var1 avant : $var1"
6 var1=100
7 echo "Dans la fonction f1 => var1 après : $var1"
8 echo "Dans la fonction f1 => var2 avant : $var2"
9 var2=200
10 echo "Dans la fonction f1 => var2 après : $var2"
11 }
12 # var1 et var2 sont des variables globales
13 var1=1
14 var2=2
15 echo "Dans le programme principal => var1 avant appel f1 : $var1"
16 echo "Dans le programme principal => var2 avant appel f1 : $var2"
17 f1
18 echo "Dans le programme principal => var1 après appel f1 : $var1"
19 echo "Dans le programme principal => var2 après appel f1 : $var2"
20 exit 0
$ ./fonction03.sh
Dans le programme principal => var1 avant appel f1 : 1
Dans le programme principal => var2 avant appel f1 : 2
Dans la fonction f1 => var1 avant :
Dans la fonction f1 => var1 après : 100
Dans la fonction f1 => var2 avant : 2
Dans la fonction f1 => var2 après : 200
Dans le programme principal => var1 après appel f1 : 1
Dans le programme principal => var2 après appel f1 : 200
$
2 variables globales var1 et var2 sont définies et initialisées ligne 13 et 14.
1 variable locale var1 est définie dans la fonction ligne 4 et initialisée à 100 ligne 6.
Après exécution de la fonction f1, la variable globale var1 a conservée sa valeur (1) alors que la variable globale var2 a été modifiée.
Dans un script shell, il est tout à fait possible de passer des arguments à une fonction étant donné qu'une fonction est reconnue par le shell comme étant une commande à part entière.
Ces arguments sont récupérables dans les fonctions grâce aux variables spéciales $1, $2, $3, ....., ${10} ......$*, $@ et $#. Ces variables sont aussi locales aux fonctions.
Par contre, la variable $0 contient toujours le nom du script.
Exemple :
$ nl fonction04.sh
1 #!/bin/bash
2 function f1 {
3 echo "Arguments de la fonction f1 :"
4 echo "\$0 => $0"
5 echo "\$1 => $1"
6 echo "\$2 => $2"
7 echo "\$3 => $3"
8 echo "\$* => $*"
9 echo "\$# => $#"
10 }
11 function f2 {
12 echo "Arguments de la fonction f2 :"
13 echo "\$0 => $0"
14 echo "\$1 => $1"
15 echo "\$2 => $2"
16 echo "\$3 => $3"
17 echo "\$* => $*"
18 echo "\$# => $#"
19 }
20 function f3 {
21 echo "Arguments de la fonction f3 :"
22 echo "\$0 => $0"
23 echo "\$1 => $1"
24 echo "\$2 => $2"
25 echo "\$3 => $3"
26 echo "\$* => $*"
27 echo "\$# => $#"
28 }
29 echo "Arguments du programme principal :"
30 echo "\$0 => $0"
31 echo "\$1 => $1"
32 echo "\$2 => $2"
33 echo "\$3 => $3"
34 echo "\$* => $*"
35 echo "\$# => $#"
36 # Appel de la fonction f1 avec 3 arguments
37 f1 a b c
38 # Appel de la fonction f2 avec 3 arguments
39 f2 file.c 2000 500
40 # Appel de la fonction f3 avec 2 arguments provenant du programme principal
41 f3 $2 $3
42 exit 0
$
Appel du script fonction04.sh avec 3 arguments :
$ ./fonction04.sh arg1 arg2 arg3
Arguments du programme principal :
$0 => ./fonction04.sh
$1 => arg1
$2 => arg2
$3 => arg3
$* => arg1 arg2 arg3
$# => 3
Arguments de la fonction f1 :
$0 => ./fonction04.sh
$1 => a
$2 => b
$3 => c
$* => a b c
$# => 3
Arguments de la fonction f2 :
$0 => ./fonction04.sh
$1 => file.c
$2 => 2000
$3 => 500
$* => file.c 2000 500
$# => 3
Arguments de la fonction f3 :
$0 => ./fonction04.sh
$1 => arg2
$2 => arg3
$3 =>
$* => arg2 arg3
$# => 2
$
Comme n'importe quelle commande renvoyant un résultat, une fonction peut également être placée à l'intérieur de caractères de substitution de commande `` ou $( ).
Exemple :
$ nl fonction05.sh
1 #!/bin/bash
2 function getUid {
3 grep "^$1:" /etc/passwd | cut -d':' -f3
4 }
5 # Initialisation de la variable globale uid
6 uid=""
7 # Appel de la fonction getUid avec l'argument du programme principal
8 # Juste pour l'affichage
9 getUid $1
10 # Affectation du résultat de la fonction getUid à la variable uid
11 uid=$(getUid $1)
12 if [[ $uid != "" ]]
13 then
14 echo "L'utilisateur $1 a pour UID : $uid"
15 else
16 echo "L'utilisateur $1 n'existe pas"
17 fi
18 exit 0
$ ./fonction05.sh root
0
L'utilisateur root a pour UID : 0
$
Exemple d'un script reprenant toutes les commandes et fonctions vues précédement
$ nl fonction06.sh
1 #!/bin/bash
2 # Pour faire une pause
3 function pause {
4 echo "Appuyer sur Entrée pour continuer"
5 read x
6 }
7 # Pour savoir si un utilisateur existe
8 function existUser {
9 grep -qi "^$1:" /etc/passwd && return 0
10 return 1
11 }
12 # Pour connaitre l'uid de l'utilisateur
13 function getUid {
14 grep -i "^$1:" /etc/passwd | cut -d':' -f3
15 }
16 # Initialisation des variables globales
17 uid=""
18 user=""
19 choix=""
20 while true
21 do
22 clear
23 echo "- 1 - Savoir si un utilisateur existe"
24 echo "- 2 - Connaitre l'UID d'un utilisateur"
25 echo "- 3 - Fin"
26 echo -e "Votre choix : \c"
27 read choix
28 if [[ $choix = @(1|2) ]] ; then
29 echo -e "Saisir le nom d'un utilisateur : \c"
30 read user
31 fi
32 case $choix in
33 1) if existUser $user ; then
34 echo "L'utilisateur $user existe"
35 else
36 echo "l'utilisateur $user n'existe pas"
37 fi
38 ;;
39 2) if existUser $user ; then
40 uid=$(getUid $user)
41 echo "l'UID de l'utilisateur $user est : $uid"
42 else
43 echo "L'utilisateur $user n'existe pas"
44 fi
45 ;;
46 3) exit 0
47 ;;
48 esac
49 pause
50 done
$
En KSH, la commande print apporte des fonctionnalités supplémentaires à la commande echo.
Exemple :
Utilisation simple
$ print coucou
coucou
$
Supprimer le saut de ligne
$ print -n coucou
coucou$
Afficher des arguments commançant par le caractère "-"
$ print - "-i : Option invalide"
-i : Option invalide
$
Ecrire sur un descripteur particulier
$ print -u2 "Message d'erreur"
Message d'erreur
$
Comparaison avec la commande echo
$ echo "Message d'erreur" 1>&2
Message d'erreur
$
En BASH, cette commande est identique à celle du langage C.
Elle permet de formater les affichages.
Syntaxe :
printf chaine expr1 expr2 ..... exprn
chaine représente la chaîne qui sera affichée à l'écran.
Elle peut contenir des formats qui seront substitués par la valeur des expressions citées à sa suite.
Il doit y avoir autant de formats que d'expressions.
Exemple de formats utilisés.
%20s | Affichage d'une chaine (string) sur 20 positions avec cadrage à droite |
%-20s | Affichage d'une chaine (string) sur 20 positions avec cadrage à gauche |
%3d | Affichage d'un entier (décimal) sur 3 positions avec cadrage à droite |
%03d | Affichage d'un entier (décimal) sur 3 positions avec cadrage à droite et complété avec des 0 à gauche |
%-3d | Affichage d'un entier (décimal) sur 3 positions avec cadrage à gauche |
%+3d | Affichage d'un entier (décimal) sur 3 positions avec cadrage à droite et affichage systématique du signe (un nombre négatif est toujours affiché avec son signe) |
%10.2f | Affichage d'un nombre flottant sur 10 positions dont 2 décimales |
%+010.2f | Affichage d'un nombre flottant sur 10 positions dont 2 décimales, complété par des 0 à gauche, avec cadrage à droite et affichage systématique du signe |
Exemple :
$ article="Livres"
$ quantite=3
$ prix=3,5
$ printf "%-20s***%03d***%+10.2f\n" $article $quantite $prix
Livres ***003*** +3,50
$
En utilisant un tableau
$ liste=(livre 10 3,5 cd 5 10,65 dvd 7 19,70 bd 80 5,25)
$ printf "%-20s***%03d***%+10.2f\n" ${liste[*]}
livre ***010*** +3,50
cd ***005*** +10,65
dvd ***007*** +19,70
bd ***080*** +5,25
$
La commande interne exec permet de manipuler les descripteurs de fichier du shell courant.
Utilisée à l'intérieur d'un script, elle permet de rediriger de manière globale les entrées/sorties de celui-ci.
Rediriger l'entrée standard d'un script :
exec 0< fichier1
Toutes les commandes du script placées après cette directive et qui lisent leur entrée standard vont extraire leurs données à partir de fichier1.
Il n'y aura donc pas d'interaction avec le clavier.
Rediriger la sortie standard et la sortie d'erreur standard d'un script :
exec 1> fichier1 2> fichier2
Toutes les commandes du script placées après cette directive et qui écrivent sur leur sortie standard enverront leurs résultat dans fichier1.
Celles qui écrivent sur leur sortie d'erreur standard enverront leurs erreurs dans fichier2.
Rediriger la sortie standard et la sortie d'erreur standard d'un script dans un même fichier :
exec 1> fichier1 2>&1
Toutes les commandes du script placées après cette directive enverront leurs résultats et leurs erreurs dans fichier1
Premier exemple :
Redirection de la sortie standard vers /tmp/fichier1.log et redirection de la sortie d'erreur standard vers /tmp/fichier2.log.
$ nl test.sh
1 #!/bin/bash
2 exec 1> /tmp/fichier1.log 2> /tmp/fichier2.log
3 echo "Début du traitement : $(date)"
4 ls
5 cp *.zzz /tmp
6 rm *.zzz
7 sleep 5
8 echo "Fin du traitement : $(date)"
9 exit 0
$
Exécution du script.
$ ./test.sh
$
Affichage du fichier /tmp/fichier1.log
$ nl /tmp/fichier1.log
1 Début du traitement : lundi 12 décembre 2011, 08:23:33 (UTC+0100)
2 1coucou
3 24902
4 25013
5 25031
6 25043
7 boucleFor01.sh
8 boucleFor02.sh
9 boucleUntil01.sh
.....
87 Fin du traitement : lundi 12 décembre 2011, 08:23:38 (UTC+0100)
$
Affichage du fichier /tmp/fichier2.log (les fichiers *.zzz n'exsistant pas, 2 erreurs sont générées)
$ nl /tmp/fichier2.log
1 cp: impossible d'évaluer «*.zzz»: Aucun fichier ou dossier de ce type
2 rm: impossible de supprimer «*.zzz»: Aucun fichier ou dossier de ce type
$
Deuxième exemple :
Redirection de la sortie standard et de la sortie d'erreur standard vers le fichier /tmp/fichier3.log
$ nl ./test2.sh
1 #!/bin/bash
2 exec 1> /tmp/fichier3.log 2>&1
3 echo "Début du traitement : $(date)"
4 ls
5 cp *.zzz /tmp
6 rm *.zzz
7 sleep 5
8 echo "Fin du traitement : $(date)"
9 exit 0
$
Exécution du script
$ ./test2.sh
$
Affichage du fichier /tmp/fichier3.log
$ nl /tmp/fichier3.log
1 Début du traitement : lundi 12 décembre 2011, 12:56:35 (UTC+0100)
2 1coucou
3 24902
4 25013
5 25031
6 25043
.....
88 cp: impossible d'évaluer «*.zzz»: Aucun fichier ou dossier de ce type
89 rm: impossible de supprimer «*.zzz»: Aucun fichier ou dossier de ce type
90 Fin du traitement : lundi 12 décembre 2011, 12:56:40 (UTC+0100)
$
Troisième exemple :
Redirection de l'entrée standard
$ nl test3.sh
1 #!/bin/bash
2 exec 0< /etc/passwd
3 cpt=1
4 while read ligne
5 do
6 echo "Lecture de la ligne $cpt"
7 echo $ligne
8 ((cpt+=1))
9 done
10 exit 0
$
Exécution du script
$ ./test3.sh
Lecture de la ligne 1
root:x:0:0:root:/root:/bin/bash
Lecture de la ligne 2
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
Lecture de la ligne 3
bin:x:2:2:bin:/bin:/bin/sh
Lecture de la ligne 4
sys:x:3:3:sys:/dev:/bin/sh
Lecture de la ligne 5
sync:x:4:65534:sync:/bin:/bin/sync
Lecture de la ligne 6
games:x:5:60:games:/usr/games:/bin/sh
Lecture de la ligne 7
man:x:6:12:man:/var/cache/man:/bin/sh
.....
$
Les shells récents apportent une fonctionnalité supplémentaire.
La possibilité d'ouvrir et de manipuler des fichiers en utilisant des descripteurs compris entre 3 et 9 (en supplément de 0, 1 et 2).
L'avantage est de pouvoir manipuler des fichiers tout en conservant les descripteurs 0, 1 et 2 connectés sur le terminal.
En lecture
exec desc <fichier
En écriture
exec desc>fichier
read variable1 variable2 ..... variablen <&desc
ou
read -udesc variable1 variable2 ..... variablen
echo variable1 variable2 ..... variablen >&desc
ou
print -udesc variable1 variable2 ..... variablen
Syntaxe :
Ouvert en lecture
exec desc<&-
Ouvert en écriture
exec desc>&-
$ nl test4.sh
1 #!/bin/bash
2 # Ouverture du fichier /etc/passwd en lecture sous le descripteur 3
3 # et du fichier /tmp/resultat.log en écriture sous le descripteur 4
4 exec 3</etc/passwd 4>/tmp/resultat.log
5 cpt=1
6 # Lecture ligne par ligne du fichier /etc/passwd
7 # correspondant au descripteur 3
8 while read -u3 ligne
9 do
10 # Ecriture des données dans le fichier /tmp/resultat.log
11 # correspondant au descripteur 4
12 echo "Ecriture de la ligne $cpt" >&4
13 echo $ligne >&4
14 ((cpt+=1))
15 done
16 # Fermeture du fichier /etc/passwd correspondant au descripteur 3
17 exec 3<&-
18 # Fermeture du fichier /tmp/resultat.log correspondant au descripteur 4
19 exec 4>&-
20 exit 0
$
Résultat :
$ ./test4.sh
$ nl /tmp/resultat.log
1 Ecriture de la ligne 1
2 root:x:0:0:root:/root:/bin/bash
3 Ecriture de la ligne 2
4 daemon:x:1:1:daemon:/usr/sbin:/bin/sh
5 Ecriture de la ligne 3
6 bin:x:2:2:bin:/bin:/bin/sh
7 Ecriture de la ligne 4
8 sys:x:3:3:sys:/dev:/bin/sh
9 Ecriture de la ligne 5
10 sync:x:4:65534:sync:/bin:/bin/sync
11 Ecriture de la ligne 6
12 games:x:5:60:games:/usr/games:/bin/sh
13 Ecriture de la ligne 7
14 man:x:6:12:man:/var/cache/man:/bin/sh
.....
$
Les redirections peuvent également être faites au moment de l'exécution du script.
Exemple :
Avec le script suivant
$ nl test5.sh
1 #!/bin/bash
2 cpt=1
3 # Lecture ligne par ligne du fichier passé en paramètre
4 # ou lecture de la saisie clavier si pas de fichier en paramètre
5 while read ligne
6 do
7 # Ecriture des données dans le fichier passé en paramètre
8 # ou affichage à l'écran si pas de fichier en paramètre
9 echo "Ecriture de la ligne $cpt"
10 echo $ligne
11 ((cpt+=1))
12 done
13 exit 0
$
Exécution du script sans paramètre
$ ./test5.sh
saisie 1 # saisie
Ecriture de la ligne 1
saisie 1
saisie 2 # saisie
Ecriture de la ligne 2
saisie 2
saisie 3 # saisie
Ecriture de la ligne 3
saisie 3
^d
$
Exécution du script avec paramètre en entrée
$ ./test5.sh < /etc/passwd
Ecriture de la ligne 1
root:x:0:0:root:/root:/bin/bash
Ecriture de la ligne 2
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
Ecriture de la ligne 3
bin:x:2:2:bin:/bin:/bin/sh
Ecriture de la ligne 4
sys:x:3:3:sys:/dev:/bin/sh
Ecriture de la ligne 5
sync:x:4:65534:sync:/bin:/bin/sync
Ecriture de la ligne 6
games:x:5:60:games:/usr/games:/bin/sh
Ecriture de la ligne 7
man:x:6:12:man:/var/cache/man:/bin/sh
.....
$
Exécution du script avec paramètres en entrée et en sortie
$ ./test5.sh < /etc/passwd > /tmp/resultat.log
$ nl /tmp/resultat.log
1 Ecriture de la ligne 1
2 root:x:0:0:root:/root:/bin/bash
3 Ecriture de la ligne 2
4 daemon:x:1:1:daemon:/usr/sbin:/bin/sh
5 Ecriture de la ligne 3
6 bin:x:2:2:bin:/bin:/bin/sh
7 Ecriture de la ligne 4
8 sys:x:3:3:sys:/dev:/bin/sh
9 Ecriture de la ligne 5
10 sync:x:4:65534:sync:/bin:/bin/sync
11 Ecriture de la ligne 6
12 games:x:5:60:games:/usr/games:/bin/sh
13 Ecriture de la ligne 7
14 man:x:6:12:man:/var/cache/man:/bin/sh
.....
$
Les redirections d'entrée (0) et de sortie (1) standards peuvent également être faite à l'intérieur du script.
Exemple :
Avec le script suivant
$ nl test6.sh
1 #!/bin/bash
2 exec </etc/passwd >/tmp/resultat.log
3 cpt=1
4 while read ligne
5 do
6 echo "Ecriture de la ligne $cpt"
7 echo $ligne
8 ((cpt+=1))
9 done
10 exit 0
$
Exécution du script et affichage du résultat
$ ./test6.sh
$ nl /tmp/resultat.log
1 Ecriture de la ligne 1
2 root:x:0:0:root:/root:/bin/bash
3 Ecriture de la ligne 2
4 daemon:x:1:1:daemon:/usr/sbin:/bin/sh
5 Ecriture de la ligne 3
6 bin:x:2:2:bin:/bin:/bin/sh
7 Ecriture de la ligne 4
8 sys:x:3:3:sys:/dev:/bin/sh
9 Ecriture de la ligne 5
10 sync:x:4:65534:sync:/bin:/bin/sync
11 Ecriture de la ligne 6
12 games:x:5:60:games:/usr/games:/bin/sh
13 Ecriture de la ligne 7
14 man:x:6:12:man:/var/cache/man:/bin/sh
.....
$
Il est également possible de rediriger uniquement les commandes situées à l'intérieur d'une structure de contrôle.
Les redirections doivent être écrites derrière le mot clé qui ferme la structure de contrôle.
A l'exécution, elles sont mises en place avant le traitement de la structure de contrôle.*
Exemple :
Dans le script suivant, seules les commandes situées à l'intérieur de la boucle while seront redirigées.
$ nl test7.sh
1 #!/bin/bash
2 echo "Lancement du script"
3 cpt=1
4 while read ligne
5 do
6 echo "Ecriture de la ligne $cpt"
7 echo $ligne
8 ((cpt+=1))
9 done </etc/passwd >/tmp/resultat.log
10 exit 0
$ ./test7.sh
Lancement du script
$ nl /tmp/resultat.log
1 Ecriture de la ligne 1
2 root:x:0:0:root:/root:/bin/bash
3 Ecriture de la ligne 2
4 daemon:x:1:1:daemon:/usr/sbin:/bin/sh
5 Ecriture de la ligne 3
6 bin:x:2:2:bin:/bin:/bin/sh
$
Rediriger un bloc avec des fichiers ouverts en amont
$ nl test8.sh
1 #!/bin/bash
2 exec 3</etc/passwd 4>/tmp/resultat.log
3 echo "Lancement du script"
4 cpt=1
5 while read ligne
6 do
7 # Ecriture des données dans le fichier /tmp/resultat.log
8 # correspondant au descripteur 4
9 echo "Ecriture de la ligne $cpt"
10 echo $ligne
11 ((cpt+=1))
12 done <&3 >&4
13 echo "Fin du script"
14 exec 3<&-
15 exec 4>&-
16 exit 0
$ ./test8.sh
Lancement du script
Fin du script
$ nl /tmp/resultat.log
1 Ecriture de la ligne 1
2 root:x:0:0:root:/root:/bin/bash
3 Ecriture de la ligne 2
4 daemon:x:1:1:daemon:/usr/sbin:/bin/sh
5 Ecriture de la ligne 3
6 bin:x:2:2:bin:/bin:/bin/sh
$
Si les lignes du fichier à traiter sont structurées en champs, il est très facile de récupérer chacun de ceux ci dans une variable.
Pour cela, il faut modifier la valeur de la variable IFS.
Exemple :
Le script suivant génère, à partir du fichier /etc/passwd, un affichage à l'écran du username suivi de son uid.
La variable IFS est sauvegardée (ligne 13) afin d'être restaurée (ligne 19) et son contenu est remplacé par ":" (ligne 14).
":" étant le caractère séparant les champs du fichier /etc/passwd.
La commande read reçoit 7 variables en argument (ligne 15). Autant de variables que de champs dans le fichier /etc/passwd.
Elle découpe donc la ligne lue (ligne 18) en champs en utilisant le caractère ":" comme séparateur.
La ligne est donc automatiquement découpée et les valeurs récupérables via les variables indiquées.
$ nl test9.sh
1 #!/bin/bash
2 if (( $# != 1 ))
3 then
4 echo "Mauvais nombre d'arguments"
5 echo "Usage : $0 fichier"
6 exit 1
7 fi
8 if [[ ( ! -f "$1" ) || ( ! -r "$1" ) ]]
9 then
10 echo "$1 n'est pas un fichier ordinaire ou n'est pas accessible en lecture"
11 exit 2
12 fi
13 oldIFS="$IFS"
14 IFS=":"
15 while read username password uid gid nomComplet home shell
16 do
17 echo "$username ==> $uid"
18 done < $1
19 IFS="$oldIFS"
20 exit 0
$ ./test9.sh /etc/passwd
root ==> 0
daemon ==> 1
bin ==> 2
sys ==> 3
$
Ce script peut très bien être dirigé dans un tube et exploité avec la commande grep
$ ./test9.sh /etc/passwd | grep "root"
root ==> 0
$
Syntaxe :
eval expr1 expr2 ..... exprn
La commande eval permet de faire subir à une ligne de commande une double évaluation.
Exemple :
Initialisation de la variable nom
$ nom=toto
Initialisation de la variable var avec le nom de la variable définie ci dessus
$ var=nom
Affichage des valeurs des variables
$ echo $nom
toto
$ echo $var
nom
$ echo \$$var
$nom
$
Pour obtenir $var=toto, il faut obligatoirement utiliser la commande eval de cette manière
$ eval echo \$$var
toto
$
La commande eval évalue en premier la variable $var, le premier $ étant protégé par un anti-slash
==> eval echo \$nom
puis évalue le résultat de la première évaluation, c'est à dire $nom (suppression de l'anti-slash)
==> eval echo $nom
Initialisation de la variable var2
$ var2=\$$var
$ echo $var2
$nom
$ eval var2=\$$var
$ echo $var2
toto
$
Il est possible de modifier le comportement des signaux envoyés au shell en utilisant la commande trap.
Liste des signaux :
$ kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
$
Détail des signaux :
Dans les commandes, les signaux peuvent être exprimés sous forme numérique ou symbolique.
Les signaux HUP, INT, TERM et KILL possèdent la même valeur numérique sur toutes les plates-formes Unix, ce qui n'est pas le cas de tous les signaux.
Il est donc préférable d'utiliser la forme symbolique.
Le signal INT est généré à partir du clavier.
Il est utilisé pour tuer le processus qui tourne en avant plan.
Pour connaitre la saisie clavier correspondant au signal INT, voir le paramètre intr de la commande stty -a.
$ stty -a
speed 38400 baud; rows 36; columns 134; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S;
susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;
-parenb -parodd cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany -imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke
$
Syntaxe :
trap ' ' sig1 sig2
Exemple :
Le shell courant correspond au PID 30819
$ echo $$
30819
Modification des signaux HUP et TERM
$ trap '' HUP TERM
Envoi des signaux HUP et TERM
$ kill -HUP 30819
$ kill -TERM 30819
Les signaux sont ignorés et le processus est toujours actif
$ echo $$
30819
$
Syntaxe :
trap 'cmd1 ; cmd2 ; cmd3 ; ..... ; cmdn' sig1 sig2
Exemple :
Le shell courant correspond au PID 23217
$ ps
PID TTY TIME CMD
22109 pts/0 00:00:00 bash
23217 pts/0 00:00:00 bash
23465 pts/0 00:00:00 ps
$ echo $$
23217
Modification du traitement associé au signal ^C (ctrl+c)
On demande au shell d'afficher le message "Signal INT reçu" après avoir appuyer sur ^C (ctrl+c)
$ trap 'echo "Signal INT reçu" ; exit 1' INT
$ ^C # Saisie
$ Signal INT reçu
Le shell courant correspondant au PID 23217 n'existe plus
$ ps
PID TTY TIME CMD
22109 pts/0 00:00:00 bash
24229 pts/0 00:00:00 ps
$ echo $$
22109
$
Syntaxe :
trap - sig1 sig2 ..... sign
Exemple :
Création du fichier /tmp/fichier
$ > /tmp/fichier
$ ls /tmp/fichier
/tmp/fichier
Modification du traitement associé au signal INT et TERM
On demande au shell de supprimer le fichier "/tmp/fichier" après avoir appuyer sur ^C (ctrl+c)
$ trap 'rm -f /tmp/fichier' INT TERM
Le shell courant correspond au PID 22109
$ echo $$
22109
Envoi du signal INT "^C" (ctrl+c)
$ ^C
Le fichier a bien été suprimé
$ ls /tmp/fichier
ls: impossible d'accéder à /tmp/fichier: Aucun fichier ou dossier de ce type
Création d'un nouveau fichier /tmp/fichier
$ > /tmp/fichier
$ ls /tmp/fichier
/tmp/fichier
Traitement associé au signal INT et TERM remis par défaut
$ trap - INT TERM
Le shell courant correspond au PID 22109
$ echo $$
22109
Envoi du signal INT "^C" (ctrl+c)
$ ^C
Le fichier n'a pas été supprimé
$ ls /tmp/fichier
/tmp/fichier
$
L'utilisation de trap dans un script shell va permettre de gérer des actions en fonctions de différents signaux reçus.
Exemple :
Dans le script suivant, à la réception d'un signal HUP INT ou TERM, la fonction "fin" est appelée et le fichier $fileTmp est supprimé.
$ nl signaux.sh
1 #!/bin/bash
2
3 # Nom du fichier temporaire
4 fileTmp=/tmp/fileTemp
5
6 # Fonction appelée lors de la réception d'un signal HUP INT TERM
7 function fin {
8 echo -e "\nSuppression du fichier $fileTmp"
9 echo "Fin du script"
10 rm -f $fileTmp
11 ls $fileTmp
12 exit 1
13 }
14
15 # Paramétrage de la fonction "fin" à la réception d'un signal HUP INT TERM
16 trap fin HUP INT TERM
17
18 # Création du fichier temporaire
19 > $fileTmp
20
21 echo "Lancement du script"
22 # Vérification de la création du fichier temporaire
23 ls $fileTmp
24 sleep 100
25 echo "Arrêt du script"
26 exit 0
$
Exécution du script :
$ ./signaux.sh
Lancement du script
/tmp/fileTemp
^C # Envoi du signal
Suppression du fichier /tmp/fileTemp
Fin du script
ls: impossible d'accéder à /tmp/fileTemp: Aucun fichier ou dossier de ce type
$
Syntaxe :
select var in item1 item2 item3 ..... itemn
do
commandes
done
La commande interne select est une structure de contrôle de type boucle qui permet d'afficher de manière cyclique un menu.
La liste des items sera affichée à l'écran à chaque tour de boucle.
Les items sont indicés automatiquement.
La variable var sera initialisée avec l'item correspondant au choix de l'utilisateur.
Cette commande utilise également deux variables réservées :
La variable var contient le libellé du choix et REPLY l'indice de ce dernier.
Exemple :
$ nl select.sh
1 #!/bin/bash
2
3 function sauve {
4 echo "Lancement de la sauvegarde"
5 }
6
7 function restaure {
8 echo "Lancement de la restauration"
9 }
10
11 PS3="Votre choix : "
12
13 select item in "- Sauvegarde -" "- Restauration -" "- Fin -"
14 do
15 echo "Vous avez choisi l'item $REPLY : $item"
16 case $REPLY in
17 1)
18 # Appel de la fonction sauve
19 sauve
20 ;;
21 2)
22 # Appel de la fonction restaure
23 restaure
24 ;;
25 3)
26 echo "Fin du script"
27 exit 0
28 ;;
29 *)
30 echo "Choix incorrect"
31 ;;
32 esac
33 done
$
Exécution :
$ ./select.sh
1) - Sauvegarde -
2) - Restauration -
3) - Fin -
Votre choix : 2
Vous avez choisi l'item 2 : - Restauration -
Lancement de la restauration
La saisie de la touche [Entrée] permet de réafficher le menu :
$ .
Votre choix : # Appui sur la touche [Entrée]
1) - Sauvegarde -
2) - Restauration -
3) - Fin -
Votre choix : 3
Vous avez choisi l'item 3 : - Fin -
Fin du script
$
$ type getopts
getopts est une primitive du shell
$
Syntaxe :
getopts listeOptionsAttendues option
La commande interne getopts permet à un script d'anayser les options passées en argument.
Chaque appel à la commande getopts analyse l'option suivante de la ligne de commande.
Pour vérifier la validité de chacune des options, il faut appeler getopts à partir d'une boucle.
Pour getopts, une option est composée d'un caractère précédé du signe "+" ou "-".
Premier exemple :
$ ls -l *.sh
Par exemple, pour la commande ls, "-l" est une option et "*.sh" est un argument.
Une option peut fonctionner seule ou être associée à un argument.
Second exemple :
Le script suivant détail la manière d'utiliser la commande getopts.
$ nl test_getopts_1.sh
1 #!/bin/bash
2
3 while getopts "abcd:e:" option
4 do
5 echo "getopts a trouvé l'option $option"
6 case $option in
7 a)
8 echo "Exécution des commandes de l'option a"
9 echo "Indice de la prochaine option à traiter : $OPTIND"
10 ;;
11 b)
12 echo "Exécution des commandes de l'option b"
13 echo "Indice de la prochaine option à traiter : $OPTIND"
14 ;;
15 c)
16 echo "Exécution des commandes de l'option c"
17 echo "Indice de la prochaine option à traiter : $OPTIND"
18 ;;
19 d)
20 echo "Exécution des commandes de l'option d"
21 echo "Liste des arguments à traiter : $OPTARG"
22 echo "Indice de la prochaine option à traiter : $OPTIND"
23 ;;
24 e)
25 echo "Exécution des commandes de l'option e"
26 echo "Liste des arguments à traiter : $OPTARG"
27 echo "Indice de la prochaine option à traiter : $OPTIND"
28 ;;
29 esac
30 done
31 echo "Analyse des options terminée"
32 exit 0
$
L'appel à la commande getopts récupère l'option suivante et retourne un code vrai tant qu'il reste des options à analyser.
La liste des options utilisables avec ce script sont définies à la ligne 3 (getopts "abcd:e:" option). Il s'agit des options -a, -b, -c, -d et -e.
Le caractère ":" inscrit après les options "d" et "e" (getopts "abcd:e:" option) indique que ces options doivent être suivies obligatoirement d'un argument.
La variable "option" (getopts "abcd:e:" option) permet de récupérer la valeur de l'option en cours de traitement par la boucle while.
La variable réservée "$OPTIND" contient l'indice de la prochaine option à traiter.
La variable réservée "$OPTARG" contient l'argument associé à l'option.
Exécution du script avec des options valides :
$ ./test_getopts_1.sh -a -b -c -d toto -e tata,tutu
getopts a trouvé l'option a
Exécution des commandes de l'option a
Indice de la prochaine option à traiter : 2
getopts a trouvé l'option b
Exécution des commandes de l'option b
Indice de la prochaine option à traiter : 3
getopts a trouvé l'option c
Exécution des commandes de l'option c
Indice de la prochaine option à traiter : 4
getopts a trouvé l'option d
Exécution des commandes de l'option d
Liste des arguments à traiter : toto
Indice de la prochaine option à traiter : 6
getopts a trouvé l'option e
Exécution des commandes de l'option e
Liste des arguments à traiter : tata,tutu
Indice de la prochaine option à traiter : 8
Analyse des options terminée
$
Lorsque la commande getopts détecte une option invalide, la variable option est initialisée avec la caractère "?" et un message d'erreur est affiché à l'écran.
Les options suivantes sont analysées.
Exemple :
L'option -z ne fait pas partie de la liste des options attendues.
$ ./test_getopts_1.sh -a -z -b -c -d toto -e tata,tutu
getopts a trouvé l'option a
Exécution des commandes de l'option a
Indice de la prochaine option à traiter : 2
./test_getopts_1.sh : option non permise -- z
getopts a trouvé l'option ?
getopts a trouvé l'option b
Exécution des commandes de l'option b
Indice de la prochaine option à traiter : 4
getopts a trouvé l'option c
Exécution des commandes de l'option c
Indice de la prochaine option à traiter : 5
getopts a trouvé l'option d
Exécution des commandes de l'option d
Liste des arguments à traiter : toto
Indice de la prochaine option à traiter : 7
getopts a trouvé l'option e
Exécution des commandes de l'option e
Liste des arguments à traiter : tata,tutu
Indice de la prochaine option à traiter : 9
Analyse des options terminée
$
Si le caractère ":" est placé en première position dans la liste des options à traiter (ligne 3), les erreurs sont gérées différemment.
En cas d'option invalide :
- getopts n'affichera pas de message d'erreur.
- la variable OPTARG sera initialisée avec la valeur de l'option incorrecte (ligne 29).
Exemple :
$ nl test_getopts_1.sh
1 #!/bin/bash
2
3 while getopts ":abcd:e:" option
4 do
5 echo "getopts a trouvé l'option $option"
6 case $option in
7 a)
8 echo "Exécution des commandes de l'option a"
9 echo "Indice de la prochaine option à traiter : $OPTIND"
10 ;;
11 b)
12 echo "Exécution des commandes de l'option b"
13 echo "Indice de la prochaine option à traiter : $OPTIND"
14 ;;
15 c)
16 echo "Exécution des commandes de l'option c"
17 echo "Indice de la prochaine option à traiter : $OPTIND"
18 ;;
19 d)
20 echo "Exécution des commandes de l'option d"
21 echo "Liste des arguments à traiter : $OPTARG"
22 echo "Indice de la prochaine option à traiter : $OPTIND"
23 ;;
24 e)
25 echo "Exécution des commandes de l'option e"
26 echo "Liste des arguments à traiter : $OPTARG"
27 echo "Indice de la prochaine option à traiter : $OPTIND"
28 ;;
29 \?)
30 echo "$OPTARG : option invalide"
31 exit 1
32 ;;
33 esac
34 done
35 echo "Analyse des options terminée"
36 exit 0
$
Le message d'erreur généré automatiquement par getopts n'apparait plus et la variable $OPTARG a été substituée par la valeur de l'option incorrecte.
Ligne 29, le "?" doit être protégé par un anti-slash pour ne pas être interprété par le shell.
$ ./test_getopts_1.sh -a -z -b -c -d toto -e tata,tutu
getopts a trouvé l'option a
Exécution des commandes de l'option a
Indice de la prochaine option à traiter : 2
getopts a trouvé l'option ?
z : option invalide
$
Lorsque l'argument d'une option est absent, la variable option est initialisée avec le caractère ":" et OPTARG contient la valeur de l'option concernée (ligne 29).
Exemple :
$ nl test_getopts_1.sh
1 #!/bin/bash
2
3 while getopts ":abcd:e:" option
4 do
5 echo "getopts a trouvé l'option $option"
6 case $option in
7 a)
8 echo "Exécution des commandes de l'option a"
9 echo "Indice de la prochaine option à traiter : $OPTIND"
10 ;;
11 b)
12 echo "Exécution des commandes de l'option b"
13 echo "Indice de la prochaine option à traiter : $OPTIND"
14 ;;
15 c)
16 echo "Exécution des commandes de l'option c"
17 echo "Indice de la prochaine option à traiter : $OPTIND"
18 ;;
19 d)
20 echo "Exécution des commandes de l'option d"
21 echo "Liste des arguments à traiter : $OPTARG"
22 echo "Indice de la prochaine option à traiter : $OPTIND"
23 ;;
24 e)
25 echo "Exécution des commandes de l'option e"
26 echo "Liste des arguments à traiter : $OPTARG"
27 echo "Indice de la prochaine option à traiter : $OPTIND"
28 ;;
29 :)
30 echo "L'option $OPTARG requiert un argument"
31 exit 1
32 ;;
33 \?)
34 echo "$OPTARG : option invalide"
35 exit 1
36 ;;
37 esac
38 done
39 echo "Analyse des options terminée"
40 exit 0
$
Exécution du script en oubliant l'argument de l'option -e
$ ./test_getopts_1.sh -a -b -c -d toto -e
getopts a trouvé l'option a
Exécution des commandes de l'option a
Indice de la prochaine option à traiter : 2
getopts a trouvé l'option b
Exécution des commandes de l'option b
Indice de la prochaine option à traiter : 3
getopts a trouvé l'option c
Exécution des commandes de l'option c
Indice de la prochaine option à traiter : 4
getopts a trouvé l'option d
Exécution des commandes de l'option d
Liste des arguments à traiter : toto
Indice de la prochaine option à traiter : 6
getopts a trouvé l'option :
L'option e requiert un argument
$
Les options sont stockées dans les paramètres positionnels $1, $2 ..... $n.
Une fois que celles ci sont analysées, il est possible de s'en débarasser avec la commande shift.
Ceci est intéressant s'il reste des arguments à traiter derrière les options.
Exemple :
$ nl test_getopts_1.sh | tail
37 esac
38 done
39 echo "Analyse des options terminée"
40 echo "Avant shift : "
41 echo "Liste des arguments : $*"
42 echo "Indice de la prochaine option à traiter : $OPTIND"
43 shift $((OPTIND-1))
44 echo "Après shift : "
45 echo "Liste des arguments : $*"
46 exit 0
$
L'instruction à la ligne 43 permet de retirer les options de la liste des arguments.
L'expression OPTIND-1 représente le nombre d'options analysées, donc la valeur du décalage à réaliser.
Exécution du script avec des arguments supplémentaires :
$ ./test_getopts_1.sh -a -b -c -d toto -e tata,tutu arg1 arg2 arg3 arg4
getopts a trouvé l'option a
Exécution des commandes de l'option a
Indice de la prochaine option à traiter : 2
getopts a trouvé l'option b
Exécution des commandes de l'option b
Indice de la prochaine option à traiter : 3
getopts a trouvé l'option c
Exécution des commandes de l'option c
Indice de la prochaine option à traiter : 4
getopts a trouvé l'option d
Exécution des commandes de l'option d
Liste des arguments à traiter : toto
Indice de la prochaine option à traiter : 6
getopts a trouvé l'option e
Exécution des commandes de l'option e
Liste des arguments à traiter : tata,tutu
Indice de la prochaine option à traiter : 8
Analyse des options terminée
Avant shift :
Liste des arguments : -a -b -c -d toto -e tata,tutu arg1 arg2 arg3 arg4
Indice de la prochaine option à traiter : 8
Après shift :
Liste des arguments : arg1 arg2 arg3 arg4
$
La commande wait permet au shell d'attendre la terminaison d'un processus lancé en arrière-plan.
Syntaxes :
Attendre la terminaison du processus dont le PID est donné en argument :
wait pid1
Attendre la terminaison de tous les processus lancés en arrière-plan à partir du shell courant :
wait
Attendre la terminaison du processus dont le numéro de job est donné en argument :
wait %job
Exemples :
La commande find est lançée en arrière-plan et a pour PID 2878 :
$ find / -name /etc/passwd 1>/tmp/resu 2>/dev/null &
[1] 2878
$ jobs
[1]+ Running find / -name /etc/passwd > /tmp/resu 2> /dev/null &
$
Le shell s'endort en attendant la terminaison du processus 2878 :
$ wait 2878 # Ou wait %1
Le shell est réveillé lorsque le processus 2878 est terminé :
$ .
[1]+ Exit 1 find / -name /etc/passwd > /tmp/resu 2> /dev/null
$
Le PID de la dernière commande lançée en arrière-plan est contenu dans la variable spéciale $!
Le script suivant lance en arrière-plan une recherche du fichier /etc/passwd (ligne 3).
D'autres actions peuvent être exécutées en attendant (ligne 5 à 8) puis le shell attend la fin de la recherche (ligne 9) avant d'afficher à l'écran le contenu du fichier /tmp/resu (ligne 12).
$ nl test_wait_1.sh
1 #!/bin/bash
2
3 find / -name /etc/passwd 1>/tmp/resu 2>&1 &
4 echo "Le PID du script lancé en arrière-plan est le : $!"
5 echo "Début des autres commandes"
6
7 echo "Fin des autres commandes"
8 echo "Recherche en cours - Attente de la fin de la recherche"
9 wait $!
10 echo "La recherche est terminée"
11 echo "Affichage du résultat"
12 most /tmp/resu
13 exit 0
$
$ ./test_wait_1.sh
Le PID du script lancé en arrière-plan est le : 11697
Début des autres commandes
Fin des autres commandes
Recherche en cours - Attente de la fin de la recherche
..... # Le shell s'endort
.....
La recherche est terminée
Affichage du résultat
$
Pré-requis pour que le script suivant fonctionne :
1 - Paramétrer sur le poste à sauvegarder un accès ssh au serveur de sauvegarde via un système d'authentification par clé privée / publique.
Tout est expliqué ici : http://quennec.fr/linux/utilisation/connexion-a-une-machine-distante-sans-saisir-le-mot-de-passe
2 - Le programme bzip2 doit être installé sur le poste à sauvegarder.
$ apt-get install bzip2
3 - Rendre les scripts exécutables
$ chmod +x uploadBackup.sh && chmod +x fonctions.inc.sh
Script d'archivage incrémental et transfert sftp automatique
Ce script permet d'effectuer une sauvegarde incrémentale d'un répertoire vers un serveur de sauvegarde.
Il utilise un système de niveau correspondant au jour du mois - 1.
Tous les 1er de chaque mois, une sauvegarde totale (niveau 0) est effectuée.
Une sauvegarde incrémentale est effectuée les jours suivants.
Le script est composé de 2 fichiers.
Un fichier comportant le script principal (uploadBackup.sh) et un fichier comportant les fonctions personnalisées utiles au script principal (fonctions.inc.sh).
Les fichiers à sauvegarder (variable DATADIR) sont enregistrés dans une archive CPIO compressée avec BZIP2 et stockée dans un répertoire local sur le poste à sauvegarder (variable ARCHIVEDIR).
Avant chaque sauvegarde, un fichier de niveau est créé dans le répertoire local.
Toutes les logs sont enregistrées dans un fichier stocké également dans le répertoire local.
La sauvegarde incrémentale utilise le fichier niveau précédent afin de sauvegarder tous les fichiers modifiés depuis la sauvegarde précédente grâce à la commande find et l'option -newer.
Enfin, l'archive CPIO est envoyée sur le serveur de sauvegarde (variable serveur_sauvegarde) via SFTP et stockée dans des sous-répertoires correspondant à l'année et au mois de la sauvegarde dans le dossier de sauvegarde (variable dossier_distant) .
Détail du fichier uploadBackup.sh
$ nl uploadBackup.sh
1 #!/bin/bash
2 # set -x
3 # Répertoire des scripts shell
4 SCRIPTDIR="/root/script_archivage_incremental"
5 # Répertoire des fichiers à sauvegarder
6 DATADIR="/root/dossier_a_sauvegarder"
7 # Répertoire local des archives
8 ARCHIVEDIR="/root/local_backup"
9 # Inclure les fonctions
10 . $SCRIPTDIR/fonctions.inc.sh
11 # Fichier de log
12 LOG=$ARCHIVEDIR/`getDate`.log
13 # Redirection de toutes les sorties du script vers le fichier de log
14 exec 1>$LOG 2>&1
15 # Déterminer le niveau de sauvegarde
16 # Le 1er du mois => niveau 0
17 jourDuMois=`getDayForCalcul`
18 ((niveau=$jourDuMois-1))
19 case $niveau in
20 0) # Sauvegarde totale
21 # Nettoyage du répertoire d'archive
22 rm -i $ARCHIVEDIR/*.bz2 $ARCHIVEDIR/niveau*
23 # Création du fichier de niveau (niveau 0)
24 touch $ARCHIVEDIR/niveau0
25 archive="$ARCHIVEDIR/`getDate`_niveau0.cpio"
26 find $DATADIR | cpio -ocv | bzip2 -c > $archive.bz2
27 ;;
28 *)
29 # Creation du fichier de niveau
30 touch $ARCHIVEDIR/niveau$niveau
31 archive="$ARCHIVEDIR/`getDate`_niveau${niveau}.cpio"
32 # Determination du niveau precedent
33 ((niveauPrec=$niveau-1))
34 # Test si le fichier de niveau precedent existe
35 if [[ ! -f $ARCHIVEDIR/niveau$niveauPrec ]]
36 then
37 # Si il n'existe pas, sauvegarde integrale du repertoire
38 echo "Fichier de niveau $niveauPrec inexistant"
39 echo "Execution d'une sauvegarde integrale en cours de mois"
40 find $DATADIR | cpio -ocv | bzip2 -c > $archive.bz2
41 else
42 # Sauvegarde incrementale
43 find $DATADIR -newer $ARCHIVEDIR/niveau$niveauPrec | cpio -ocv | bzip2 -c > $archive.bz2
44 fi
45 ;;
46 esac
47 # Vérification de la validité de l'archive
48 if isArchiveInvalide $archive.bz2 ; then
49 echo "Archive $archive.bz2 INVALIDE - Fichier non transfere"
50 exit 1
51 fi
52 # Transfert du fichier vers le serveur de sauvegarde
53 if transfert ${archive}.bz2 ; then
54 echo "Transfert realise avec succes"
55 exit 0
56 fi
57 # Si le transfert a echoue
58 echo "Echec de transfert"
59 exit 1
$
Détail du fichier fonctions.inc.sh
$ nl fonctions.inc.sh
1 #!/bin/bash
2 function transfert {
3 typeset mois
4 typeset annee
5 # Recuperation de la valeur du premier argument passe a la fonction
6 # Recuperation du nom de l'archive a envoyer au serveur de sauvegarde
7 typeset ficATransferer=$1
8 # Adresse du serveur de sauvegarde
9 typeset serveur_sauvegarde="192.168.1.113"
10 # Compte utilise pour se connecter au serveur de sauvegarde
11 typeset user="root"
12 # Chemin absolu du dossier ou sera stocke la sauvegarde
13 typeset dossier_distant="/root/sauvegarde_dossier"
14 mois=`getMonth`
15 annee=`getYear`
16 # Test si le dossier de sauvegarde existe sur le serveur de sauvegarde
17 # Connexion au serveur avec le user root
18 ssh $user@$serveur_sauvegarde test -d $dossier_distant/$annee/$mois
19 # Test sur le code retour de la commande precedente
20 case $? in
21 0)
22 ;;
23 255)
24 echo "Echec de la commande SSH"
25 return 1
26 ;;
27 *)
28 # Si code retour different de 0 et 255
29 # Creation du repertoire de la sauvegarde
30 ssh $user@$serveur_sauvegarde mkdir -p $dossier_distant/$annee/$mois
31 ;;
32 esac
33 # Connexion au serveur de sauvegarde en FTP sécurisé
34 # Ne pas oublier les doubles chevrons << avant le mot cle FIN
35 # Ne pas mettre d'espace entre << et FIN
36 sftp -b - $user@$serveur_sauvegarde <<FIN
37 # Positionnement dans le repertoire de la sauvegarde
38 cd $dossier_distant/$annee/$mois
39 pwd
40 # Envoi de la sauvegarde
41 put $ficATransferer
42 FIN
43 # Ne pas mettre de tabulation ou d'espace devant le mot clé FIN
44 # Sinon celui-ci n'est pas reconnu
45 # Test sur le code retour de la commande SFTP
46 # Si le code retour est different de 0
47 # Une anomalie a ete rencontree
48 (( $? != 0 )) && return 1
49 # Tester si archive valide sur serveur de sauvegarde
50 ficSurMachineCible=$(basename $ficATransferer)
51 ssh $user@$serveur_sauvegarde bzip2 -t $dossier_distant/$annee/$mois/$ficSurMachineCible
52 case $? in
53 0)
54 ;;
55 255)
56 echo "Echec de la commande SSH"
57 return 1
58 ;;
59 *)
60 # Si code retour different de 0 et 255
61 # Alors l'archive est invalide
62 echo "Archive $dossier_distant/$annee/$mois/$ficSurMachineCible INVALIDE"
63 return 1
64 ;;
65 esac
66 return 0
67 }
68 function isArchiveInvalide {
69 typeset archive=$1
70 bzip2 -t $archive 2>/dev/null && return 1
71 return 0
72 }
73 function getDate {
74 date '+%Y_%m_%d'
75 }
76 function getYear {
77 date '+%Y'
78 }
79 function getMonth {
80 date '+%m'
81 }
82 function getDayForCalcul {
83 date '+%e' | sed 's/ //'
84 }
$
Les expressions régulières sont utilisées par un certain nombre de commandes UNIX.
Les expressions régulières sont composées de caractères ordinaires et de caractères spéciaux qui ont une signification particulière.
Il existe 2 types d'expressions régulières :
Les ERb sont utilisées par les commandes suivantes :
Les ERe sont utilisées par les commandes suivantes :
Le tableau suivant liste les caractères spéciaux communs aux ERb et aux ERe
Caractère spécial | Signification |
---|---|
^ | Début de ligne |
$ | Fin de ligne |
. (point) | Un caractère quelconque |
[liste_de_caractères] | Un caractère cité dans la liste |
[^liste_de_caractères] | Un caractère qui n'est pas cité dans la liste |
* | 0 à n fois le caractère ou regroupement précédent |
\<expression | Début d'un mot. Caractères pouvant faire partie d'un mot : [A-Za-z0-9_] |
expression\> | Fin d'un mot |
\<expression\> | Mot complet |
\c | Protection du caractère spécial "c" |
Exemples :
Les expressions "space" et "tab" représentent les touches [espace] et [tabulation].
La tabulation est représentée par les caractères "\t".
Expression régulière | Signification |
---|---|
soleil | Chaine contenant "soleil". Exemple de correspondance : Aujourd'hui il y a du soleil, mais demain il pleut ! soleil toujours. Passer ses vacances au soleil. |
^soleil | Chaine commençant par "soleil". Exemple de correspondance : soleil toujours. |
soleil$ | Chaine se terminant par "soleil". Exemple de correspondance : Passer ses vacances au soleil. |
^[A-Z][5-9].$ | Chaine composée de 3 caractères. Le premier est une majuscule, le second est un chiffre entre 5 et 9 et le dernier un caractère quelconque. Exemple de correspondance : B6z Z5* |
^$ | Chaine vide (aucun caractère entre ^ et $) |
^[space tab]*$ | Chaine contenant entre 0 et n caractères espace ou tabulation |
7space[0-79]A* | Chaine contenant le chiffre 7, suivi d'un espace, suivi de n'importe quel chiffre sauf 8, suivi de la lettre A 0 à n fois. Exemple de correspondance : x7 6 abc7 9Axy 7 1AAAAAAAAAAAAAAAAbfgddghjgdhj |
[0-9][^A-Z_]$ | Chaine dont l'avant dernier caractère est un chiffre et le dernier n'est ni une lettre majuscule ni un caractère souligné. Exemple de correspondance : AZER1a 3* 440008b |
\<tout | Chaine contenant un mot commençant par "tout". Exemple de correspondance : bonjour tout le monde il faut dire toutefois Exemple de non correspondance : partout dans le monde |
\<tout\> |
Chaine contenant le mot "tout". |
[0-9][0-9]\.[0-9] | Chaine contenant 2 chiffres suivi du caractère . (point) suivi d'un chiffre. Exemple de correspondance : 4576.45 |
Les marqueurs ^ et $ perdent leur signification s'ils ne sont pas placés respectivement en début et en fin de l'expression régulière.
Caractère spécial | Signification |
---|---|
\{n\} | n fois le caractère précédent |
\{n,\} | Au moins n fois le caractère précédent |
\{n,x\} | Entre n et x fois le caractère précédent |
\(ERb\) | Mémorisation d'une ERb |
\1, \2, ... | Rappel de mémorisation |
Dans les ERB, le caractère "\" donne une signification spéciale aux parenthèses et accolades.
Exemple :
Expression régulière | Signification |
---|---|
\-[A-Z]\{2\}\- | Chaine contenant un mot de 2 lettres majuscules entouré par des tirets (-) Exemples de correspondance : BOUCHES-DU-RHONE EURE-ET-LOIR VAL-DE-MARNE |
Avec la commande grep (ou autre), le tiret (-) doit être protégé par un antislash (\) pour éviter d'être interprété comme une option.
Caractère spécial | Signification |
---|---|
? | 0 ou 1 fois le caractère ou regroupement précédent |
+ | 1 à n fois le caractère ou regroupement précédent |
{n} | n fois le caractère ou regroupement précédent |
{n,} | Au moins n fois le caractère ou regroupement précédent |
{n,x} | Entre n et x fois le caractère ou regroupement précédent |
(er1) | Regroupement |
er1 | er2 | er3 | Alternatives |
Dans les ERe, les accolades et parenthèses perdent leur signification spéciale si elles sont précédées d'un antislash.
Exemples :
Expression régulière | Signification |
---|---|
^[+-]?[0-9]+$ |
Chaine représentant un nombre entier d'au moins 1 chiffre précédé éventuellement du signe + ou - |
\([a-zA-Z]{3}\) | Chaine contenant 3 lettres minuscules et/ou majuscules et entourés de parenthèses. Exemple de correspondance : HERBIERS (Les) Herbiers |
\([-a-zA-Z _]{4,}\) | Chaine contenant au moins 4 caractères composées de lettres minuscules et/ou majuscules, de tiret (-), d'espace et de tiret bas (_) et le tout entouré de parenthèses. Exemples de correspondance : 1er (Ouest) CASTILLON (CANTON DE LEMBEYE) 2e (Nord-Ouest) |
^41|yotte$ | Chaine commençant par "41" ou finissant par "yotte" Exemples de correspondance : 41 57 57463 3 MOSELLE Moselle 41 88 88160 4 VOSGES Vosges 06 976 97608 0 MAYOTTE Mayotte |
(in|re)+ |
Chaine composée de 1 à n occurences de "in" ou de "re" (en minuscule) |
La commande grep permet l'utilisation d'expressions régulières normalisées par POSIX.
Par défaut, la commande grep utilise les ERb.
Associée à l'option -E, elle utilise les ERe.
Exemples :
Avec le fichier depts2012.txt (téléchargeable sur le site de l'INSEE à cette adresse : http://www.insee.fr/fr/methodes/nomenclatures/cog/telechargement.asp)
$ head depts2012.txt && tail depts2012.txt
REGION DEP CHEFLIEU TNCC NCC NCCENR
82 01 01053 5 AIN Ain
22 02 02408 5 AISNE Aisne
83 03 03190 5 ALLIER Allier
93 04 04070 4 ALPES-DE-HAUTE-PROVENCE Alpes-de-Haute-Provence
93 05 05061 4 HAUTES-ALPES Hautes-Alpes
93 06 06088 4 ALPES-MARITIMES Alpes-Maritimes
82 07 07186 5 ARDECHE Ardèche
21 08 08105 4 ARDENNES Ardennes
73 09 09122 5 ARIEGE Ariège
11 91 91228 5 ESSONNE Essonne
11 92 92050 4 HAUTS-DE-SEINE Hauts-de-Seine
..............
11 93 93008 3 SEINE-SAINT-DENIS Seine-Saint-Denis
11 94 94028 2 VAL-DE-MARNE Val-de-Marne
11 95 95500 2 VAL-D'OISE Val-d'Oise
01 971 97105 3 GUADELOUPE Guadeloupe
02 972 97209 3 MARTINIQUE Martinique
03 973 97302 3 GUYANE Guyane
04 974 97411 0 LA REUNION La Réunion
06 976 97608 0 MAYOTTE Mayotte
$
Rechercher la chaine "loire-atlantique" sans tenir compte de la casse :
$ cat depts2012.txt | grep -i 'loire-atlantique'
52 44 44109 3 LOIRE-ATLANTIQUE Loire-Atlantique
$
Rechercher les lignes commançant par 21 :
$ cat depts2012.txt | grep '^21'
21 08 08105 4 ARDENNES Ardennes
21 10 10387 5 AUBE Aube
21 51 51108 3 MARNE Marne
21 52 52121 3 HAUTE-MARNE Haute-Marne
$
Rechercher les lignes se terminant par "ique" :
$ cat depts2012.txt | grep -i 'ique$'
52 44 44109 3 LOIRE-ATLANTIQUE Loire-Atlantique
02 972 97209 3 MARTINIQUE Martinique
$
Rechercher les lignes ayant 2 occurences de la lettre "s" :
$ cat depts2012.txt | grep -i 'ss'
11 91 91228 5 ESSONNE Essonne
$
Idem mais avec une ERb :
$ cat depts2012.txt | grep -i 's\{2\}'
11 91 91228 5 ESSONNE Essonne
$
Idem mais avec une ERe :
$ cat depts2012.txt | grep -iE 's{2}'
11 91 91228 5 ESSONNE Essonne
$
Rechercher les lignes ayant un tiret (-) :
$ cat depts2012.txt | grep '\-'
93 04 04070 4 ALPES-DE-HAUTE-PROVENCE Alpes-de-Haute-Provence
93 05 05061 4 HAUTES-ALPES Hautes-Alpes
93 06 06088 4 ALPES-MARITIMES Alpes-Maritimes
93 13 13055 4 BOUCHES-DU-RHONE Bouches-du-Rhone
$
Rechercher les lignes contenant les chaines "loir" ou "tique" (peu importe la casse) :
$ cat depts2012.txt | grep -iE 'loir|tique'
24 28 28085 1 EURE-ET-LOIR Eure-et-Loir
24 37 37261 1 INDRE-ET-LOIRE Indre-et-Loire
24 41 41018 0 LOIR-ET-CHER Loir-et-Cher
82 42 42218 3 LOIRE Loire
83 43 43157 3 HAUTE-LOIRE Haute-Loire
52 44 44109 3 LOIRE-ATLANTIQUE Loire-Atlantique
24 45 45234 2 LOIRET Loiret
52 49 49007 0 MAINE-ET-LOIRE Maine-et-Loire
72 64 64445 4 PYRENEES-ATLANTIQUES Pyrenees-Atlantiques
26 71 71270 0 SAONE-ET-LOIRE Saone-et-Loire
$
Syntaxe :
expr chaine-de-caracteres : expression-reguliere-basique
La commande expr propose l'opérateur ":" qui permet de mettre en correspondance une chaine de caractères avec une expression régulière.
Fonctionnement de l'opérateur ":" :
Exemples :
Vérifier que la chaine saisie est un nombre.
$ read nb1
34657
$ read nb2
456G43
$
La variable nb1 contient uniquement des chiffres.
$ expr "$nb1" : '[0-9]*$' # Equivaut à '^[0-9]*$'
5
$ echo $?
0
$
La variable nb2 contient une lettre.
$ expr "$nb2" : '[0-9]*$'
0
$ echo $?
1
$
Compter le nombre de caractères contenus dans une variable.
$ chaine="Ceci est une ligne de texte"
$ expr "$chaine" : '.*'
27
$
Afficher la partie de la chaine correspondant à la mémorisation (ici, le chiffre entouré de pipe "|")
$ chaine="un|deux|trois|4|cinq|six|sept"
$ expr "$chaine" : '.*|\([0-9]\{1\}\)'
4
$
Le caractère * recherche toujours la chaine la plus longue. Le "|" le plus à droite.
$ expr "$chaine" : '\(.*\)|'
un|deux|trois|4|cinq|six
$
Solution permettant de s'arrêter au premier "|".
$ expr "$chaine" : '\([^|]*\)|'
un
$
Le script suivant test si la saisie correspond à un nombre (positif ou négatif) et effectue la somme des nombres saisis.
$ nl ./sumnb.sh
1 #!/bin/bash
2 somme=0
3 while :
4 do
5 echo -e "Saisir un nombre entier : \c"
6 if read nombre
7 then
8 if ( expr "$nombre" : '[0-9]*$' || expr "$nombre" : '-[0-9]*$' ) > /dev/null
9 then
10 somme=`expr $somme + $nombre`
11 else
12 echo "Saisie incorrecte"
13 fi
14 else
15 break
16 fi
17 done
18 echo -e "\nResultat : $somme"
19 exit 0
$
Exécution du script.
$ ./sumnb.sh
Saisir un nombre entier : 45
Saisir un nombre entier : 69
Saisir un nombre entier : er
Saisie incorrecte
Saisir un nombre entier : 9y
Saisie incorrecte
Saisir un nombre entier : 2
Saisir un nombre entier : -89
Saisir un nombre entier : ^d # Saisie clavier ctrl+d
Resultat : 27
$
La commande sed (stream editor) est un éditeur de texte non intéractif. Elle permet d'automatiser le traitement de fichiers texte.
Syntaxe de base :
sed [-n] action [fichier1 fichier2 ... fichierx]
sed [-n] -e action1 [-e action2 ...] [fichier1 fichier2 ... fichierx]
sed -f script-sed [fichier1 fichier2 ... fichierx]
Les actions spécifiées sont exécutées sur chaque ligne du ou des fichiers. Le résultat du traitement est affiché sur la sortie standard. Si plusieurs actions sont spécifiées sur la ligne de commande, chacune doit être précédée de l'option -e.
La commande sed ne modifie pas le fichier d'origine sauf si elle est exécutée avec l'option -i.
Syntaxe d'une action :
[adresse[,adresse]] commande [arguments]
Une action est syntaxiquement composée de :
Syntaxe d'une adresse :
Type d'adresse | Lignes traitées |
---|---|
Aucune adresse | Toutes les lignes |
Adresses de type 1 | |
n | Ligne n. |
$ | Dernière ligne. |
/ERb/ | Lignes correspondant à l'expression régulière |
Adresses de type 2 | |
n1, n2 | Ligne n1 jusqu'à ligne n2. |
/ERb1/,/ERb2/ | La première ligne traitée sera la première trouvée correspondant à ERb1. Le traitement se poursuivra sur toutes les lignes jusqu'à ce que sed rencontre une ligne correspondant à ERb2. Cette dernière sera également traitée. |
Syntaxe de la commande :
Commande | Argument | Type d'adresse supportée (maximum) | Signification |
---|---|---|---|
d | Aucun | 2 | Ne pas afficher les lignes spécifiées (delete). |
p | Aucun | 2 | Afficher les lignes spécifiées (print). |
s | /ERb/remplacement/[g] | 2 | Effectuer une substitution sur les lignes spécifiées (substitute). Le caractère optionnel "g" indique si la substitution doit être globale sur les lignes. |
w | fichier | 2 | Ecrire les lignes spécifiées dans un fichier (write). |
= | Aucun | 1 | Afficher le numéro de la ligne spécifiée. |
Dans les commandes ci-dessous, l'antislash rend le caractère "saut de ligne" invisible, ce qui permet de pouvoir spécifier plusieurs lignes de texte. Le dernier saut de ligne n'est pas masqué et représente la fin de la commande. | |||
a\ |
texte\[entrée] |
1 | Ajouter les lignes de texte après chaque ligne spécifiée (add). |
i\ |
texte\[entrée] texte\[entrée] texte [entrée] |
1 | Insérer les lignes de texte avant chaque ligne spécifiée (insert). |
c\ |
texte\[entrée] texte\[entrée] texte [entrée] |
2 | Remplacer les ligne spécifiées par les lignes de texte (change). |
Négation de la commande | |||
!commande | La commande s'exécutera sur toutes les lignes sauf celles spécifiées dans l'adresse. |
Exemples avec le fichier depts2012.txt (téléchargeable sur le site de l'INSEE à cette adresse : http://isbeta.fr/f8c21)
$ cat depts2012.txt
REGION DEP CHEFLIEU TNCC NCC NCCENR
82 01 01053 5 AIN Ain
22 02 02408 5 AISNE Aisne
83 03 03190 5 ALLIER Allier
93 04 04070 4 ALPES-DE-HAUTE-PROVENCE Alpes-de-Haute-Provence
93 05 05061 4 HAUTES-ALPES Hautes-Alpes
93 06 06088 4 ALPES-MARITIMES Alpes-Maritimes
82 07 07186 5 ARDECHE Ardèche
...
11 94 94028 2 VAL-DE-MARNE Val-de-Marne
11 95 95500 2 VAL-D'OISE Val-d'Oise
01 971 97105 3 GUADELOUPE Guadeloupe
02 972 97209 3 MARTINIQUE Martinique
03 973 97302 3 GUYANE Guyane
04 974 97411 0 LA REUNION La Réunion
06 976 97608 0 MAYOTTE Mayotte
$
La commande d permet de ne pas afficher à l'écran les lignes sélectionnées par la partie adresse.
Exemple :
Ne pas afficher les lignes contenant les caractères de a à h (en minuscule)
$ sed '/[a-h]/d' depts2012.txt
REGION DEP CHEFLIEU TNCC NCC NCCENR
82 01 01053 5 AIN Ain
73 46 46042 2 LOT Lot
$
La commande p permet d'afficher à l'écran les lignes sélectionnées par la partie adresse. Par défauf, sed affiche également tout le contenu du fichier. Pour modifier ce comportement, il faut utiliser l'option -n.
Exemple :
Afficher les lignes 1 à 4. Par défaut, sed affiche en plus tout le contenu du fichier. Les lignes demandées apparaissent donc en double.
$ sed '1,4p' depts2012.txt
REGION DEP CHEFLIEU TNCC NCC NCCENR
REGION DEP CHEFLIEU TNCC NCC NCCENR
82 01 01053 5 AIN Ain
82 01 01053 5 AIN Ain
22 02 02408 5 AISNE Aisne
22 02 02408 5 AISNE Aisne
83 03 03190 5 ALLIER Allier
83 03 03190 5 ALLIER Allier
93 04 04070 4 ALPES-DE-HAUTE-PROVENCE Alpes-de-Haute-Provence
93 05 05061 4 HAUTES-ALPES Hautes-Alpes
93 06 06088 4 ALPES-MARITIMES Alpes-Maritimes
....
$
L'option -n permet de ne pas afficher le reste du fichier.
$ sed -n '1,4p' depts2012.txt
REGION DEP CHEFLIEU TNCC NCC NCCENR
82 01 01053 5 AIN Ain
22 02 02408 5 AISNE Aisne
83 03 03190 5 ALLIER Allier
$
Il est également possible d'afficher 1 ligne toutes les n lignes
$ sed -n '1~4p' depts2012.txt
Cette commande permet d'afficher à partir de la ligne 1 du fichier puis toutes les 4 lignes, c'est à dire les lignes 1, 5, 9, 13 etc etc
$ sed -n '0~4p' depts2012.txt
Cette commande permet d'afficher à partir de la ligne 4 du fichier puis toutes les 4 lignes, c'est à dire les lignes 4, 8, 12, 16 etc etc
Pour info, ce type d'adressage est valable pour les commandes delete, print, write
La commande suivante permet de rechercher un motif précis et d'afficher uniquement la ligne suivante.
$ sed -n '/ANSWER SECTION/{n;p}' <(dig a quennec.fr)
quennec.fr. 906 IN A 51.159.70.99
La première partie '/ANSWER SECTION/' correspond au motif recherché.
Ensuite, '{n;p}', un bloc d'instruction qui est exécuté si le motif recherché est trouvé.
La command 'n' permet de sauter à la ligne suivante.
La commande 'p' permet d'afficher la ligne courante.
et si l'on souhaite afficher plusieurs lignes après le motif recherché
$ dig any quennec.fr | sed -n '/ANSWER SECTION/{:a ; n ; /^$/q ; p ; ba}'
quennec.fr. 3183 IN A 51.159.70.99
quennec.fr. 21400 IN NS ns42.infomaniak.com.
quennec.fr. 21400 IN NS ns41.infomaniak.com.
quennec.fr. 21400 IN SOA ns41.infomaniak.com. hostmaster.infomaniak.ch. 2024091604 10800 3600 605800 86400
quennec.fr. 3400 IN MX 5 mta-gw.infomaniak.ch.
quennec.fr. 3368 IN TXT "v=spf1 a mx ip4:99.162.140.135ip4:51.159.70.99 include:spf.infomaniak.ch -all"
Ce qui change vis à vis de la commande précédente:
Dans le bloc d'instruction '{:a ; n ; /^$/q ; p ; ba}', la première commande ':a' permet d'initialiser un label, la commande 'n' permet de passer à la ligne suivante (pas de changement), la commande '/^$/q' permet de mettre fin au traitement dès qu'une ligne vide est rencontrée, la commande 'p' permet d'afficher la ligne en cours de traitement (pas de changement), et enfin, la commande 'ba' permet de revenir au label 'a' précédement initialisé et de continuer le traitement sur la ligne suivante (à voir comme une boucle) etc etc ...
La commande w permet d'écrire dans un fichier les lignes sélectionnées par la partie adresse. Comme pour la commande p, sed affiche également tout le contenu du fichier à l'écran. Pour modifier ce comportement, il faut utiliser l'option -n.
Exemple :
Stocker dans un fichier "depts3x" toutes les villes dont le code postal commence par 3 et dans le fichier "depts6x" toutes les villes dont le code postal commence par 6.
$ sed -n -e '/3[0-9]\{4\}/w depts3x' -e '/6[0-9]\{4\}/w depts6x' depts2012.txt
$ cat depts3x
91 30 30189 2 GARD Gard
73 31 31555 3 HAUTE-GARONNE Haute-Garonne
73 32 32013 2 GERS Gers
72 33 33063 3 GIRONDE Gironde
91 34 34172 5 HERAULT Hérault
53 35 35238 1 ILLE-ET-VILAINE Ille-et-Vilaine
24 36 36044 5 INDRE Indre
24 37 37261 1 INDRE-ET-LOIRE Indre-et-Loire
82 38 38185 5 ISERE Isère
43 39 39300 2 JURA Jura
$ cat depts6x
22 60 60057 5 OISE Oise
25 61 61001 5 ORNE Orne
31 62 62041 2 PAS-DE-CALAIS Pas-de-Calais
83 63 63113 2 PUY-DE-DOME Puy-de-Dôme
72 64 64445 4 PYRENEES-ATLANTIQUES Pyrénées-Atlantiques
73 65 65440 4 HAUTES-PYRENEES Hautes-Pyrénées
91 66 66136 4 PYRENEES-ORIENTALES Pyrénées-Orientales
42 67 67482 2 BAS-RHIN Bas-Rhin
42 68 68066 2 HAUT-RHIN Haut-Rhin
82 69 69123 2 RHONE Rhône
$
Le caractère ! placé devant une commande permet d'exécuter cette dernière sur toutes les lignes sauf sur celles correspondant à la partie adresse.
Exemple :
Ne pas afficher les lignes contenant les caractères de a à h (en minuscule)
$ sed -n '/[a-h]/!p' depts2012.txt
REGION DEP CHEFLIEU TNCC NCC NCCENR
82 01 01053 5 AIN Ain
73 46 46042 2 LOT Lot
$
La commande s permet de substituer une chaine de caractères par une autre sur les lignes sélectionnées par la partie adresse.
Pour substituer des noms de fichiers avec la commande sed, utiliser le pipe '|' comme séparateur à cause du slash '/' dans les noms de fichiers.
$ sed -i "s|/fichier1|/fichier2|g" maListeDeFichiers
Premier exemple :
Remplacer toutes les chaines contenant '-et-' ou '-ET-' par ' & '
$ sed -n '/-et-/p' depts2012.txt
24 28 28085 1 EURE-ET-LOIR Eure-et-Loir
53 35 35238 1 ILLE-ET-VILAINE Ille-et-Vilaine
24 37 37261 1 INDRE-ET-LOIRE Indre-et-Loire
24 41 41018 0 LOIR-ET-CHER Loir-et-Cher
72 47 47001 0 LOT-ET-GARONNE Lot-et-Garonne
52 49 49007 0 MAINE-ET-LOIRE Maine-et-Loire
41 54 54395 0 MEURTHE-ET-MOSELLE Meurthe-et-Moselle
26 71 71270 0 SAONE-ET-LOIRE Saône-et-Loire
11 77 77288 0 SEINE-ET-MARNE Seine-et-Marne
73 82 82121 0 TARN-ET-GARONNE Tarn-et-Garonne
$
$ sed -e 's/-et-/ \& /g' -e 's/-ET-/ \& /g' depts2012.txt | sed -n '/ \& /p'
24 28 28085 1 EURE & LOIR Eure & Loir
53 35 35238 1 ILLE & VILAINE Ille & Vilaine
24 37 37261 1 INDRE & LOIRE Indre & Loire
24 41 41018 0 LOIR & CHER Loir & Cher
72 47 47001 0 LOT & GARONNE Lot & Garonne
52 49 49007 0 MAINE & LOIRE Maine & Loire
41 54 54395 0 MEURTHE & MOSELLE Meurthe & Moselle
26 71 71270 0 SAONE & LOIRE Saône & Loire
11 77 77288 0 SEINE & MARNE Seine & Marne
73 82 82121 0 TARN & GARONNE Tarn & Garonne
$
Second exemple :
Travailler sur le contenu d'une variable.
$ arg=fic1,fic2,fic3
$ echo $arg
fic1,fic2,fic3
$ echo $arg | sed 's/,/ /g' # On remplace les virgules par des espaces
fic1 fic2 fic3
$ liste_arg=$(echo $arg | sed 's/,/ /g')
$ echo $liste_arg
fic1 fic2 fic3
$ for argt in $liste_arg
> do
> echo $argt
> done
fic1
fic2
fic3
$
Troisième exemple :
Le caractère "&" utilisée dans la partie remplacement représente la chaine correspondant à l'expression régulière.
$ tail depts2012.txt
11 91 91228 5 ESSONNE Essonne
11 92 92050 4 HAUTS-DE-SEINE Hauts-de-Seine
11 93 93008 3 SEINE-SAINT-DENIS Seine-Saint-Denis
11 94 94028 2 VAL-DE-MARNE Val-de-Marne
11 95 95500 2 VAL-D'OISE Val-d'Oise
01 971 97105 3 GUADELOUPE Guadeloupe
02 972 97209 3 MARTINIQUE Martinique
03 973 97302 3 GUYANE Guyane
04 974 97411 0 LA REUNION La Réunion
06 976 97608 0 MAYOTTE Mayotte
$ tail depts2012.txt | sed 's/.*/|&|/'
|11 91 91228 5 ESSONNE Essonne|
|11 92 92050 4 HAUTS-DE-SEINE Hauts-de-Seine|
|11 93 93008 3 SEINE-SAINT-DENIS Seine-Saint-Denis|
|11 94 94028 2 VAL-DE-MARNE Val-de-Marne|
|11 95 95500 2 VAL-D'OISE Val-d'Oise|
|01 971 97105 3 GUADELOUPE Guadeloupe|
|02 972 97209 3 MARTINIQUE Martinique|
|03 973 97302 3 GUYANE Guyane|
|04 974 97411 0 LA REUNION La Réunion|
|06 976 97608 0 MAYOTTE Mayotte|
$
Toutes les chaines ont été encadrées par des pipes "|"
Quatrième exemple :
Récupérer les codes postaux et les noms des départements (en majuscule) afin d'effectuer une mise en forme particulière.
Utilisation de la mémorisation grâce aux caractères \( \) afin de les réafficher avec \1 et \2.
$ tail depts2012.txt
11 91 91228 5 ESSONNE Essonne
11 92 92050 4 HAUTS-DE-SEINE Hauts-de-Seine
11 93 93008 3 SEINE-SAINT-DENIS Seine-Saint-Denis
11 94 94028 2 VAL-DE-MARNE Val-de-Marne
11 95 95500 2 VAL-D'OISE Val-d'Oise
01 971 97105 3 GUADELOUPE Guadeloupe
02 972 97209 3 MARTINIQUE Martinique
03 973 97302 3 GUYANE Guyane
04 974 97411 0 LA REUNION La Réunion
06 976 97608 0 MAYOTTE Mayotte
$ tail depts2012.txt | sed "s/^[0-9]\{2\}[ \t]*[0-9]\{2,3\}[ \t]*\([0-9]\{5\}\)[ \t]*[0-9][ \t]*\([-A-Z_\. ']\{1,\}\)[ \t]*.\{1,\}$/Code postal : \1\tDepartement : \2/"
Code postal : 91228 Departement : ESSONNE
Code postal : 92050 Departement : HAUTS-DE-SEINE
Code postal : 93008 Departement : SEINE-SAINT-DENIS
Code postal : 94028 Departement : VAL-DE-MARNE
Code postal : 95500 Departement : VAL-D'OISE
Code postal : 97105 Departement : GUADELOUPE
Code postal : 97209 Departement : MARTINIQUE
Code postal : 97302 Departement : GUYANE
Code postal : 97411 Departement : LA REUNION
Code postal : 97608 Departement : MAYOTTE
$
Cinquième exemple :
Exemples détaillés de l'option g dans la commande de substitution s.
$ arg=val1,val2,val3,val4
$ echo $arg
val1,val2,val3,val4
Remplacement de la globalité des virgules par des espaces grâce à l'option g.
$ echo $arg | sed 's/,/ /g'
val1 val2 val3 val4
Sans l'option g, seule la première virgule rencontrée est remplacée par un espace.
$ echo $arg | sed 's/,/ /'
val1 val2,val3,val4
Le chiffre 1 permet le remplacement de la première virgule rencontrée. Identique à la commande précédente.
$ echo $arg | sed 's/,/ /1'
val1 val2,val3,val4
Le chiffre 3 permet le remplacement de la troisième virgule rencontrée.
$ echo $arg | sed 's/,/ /3'
val1,val2,val3 val4
Un script sed est un fichier texte contenant une suite d'actions sed qui seront exécutées sur les lignes d'un ou plusieurs fichiers passés en paramètre ou sur l'entrée standard de la commande sed.
Toutes les actions sont évaluées et appliquées sur toutes les lignes du ou des fichiers.
Exemple :
$ nl script.sed
1 1d
2 2i\
3 ------------------------\
4 Liste des departements :\
5 ------------------------
6 s/^[0-9]\{2\}[ \t]*[0-9]\{2,3\}[ \t]*\([0-9]\{5\}\)[ \t]*[0-9][ \t]*\([-A-Z_\. ']\{1,\}\)[ \t]*.\{1,\}$/Code postal : \1\tDepartement : \2/
7 s/^[0-9]\{2\}[ \t]*[0-9][A-B][ \t]*\([0-9][A-B][0-9]\{3\}\)[ \t]*[0-9][ \t]*\([-A-Z_\. ']\{1,\}\)[ \t]*.\{1,\}$/Code postal : \1\tDepartement : \2/
8 $a\
9 ---------------\
10 Fin de la liste\
11 ---------------
$
$ sed -f script.sed depts2012.txt
------------------------
Liste des departements :
------------------------
Code postal : 01053 Departement : AIN
Code postal : 02408 Departement : AISNE
Code postal : 03190 Departement : ALLIER
Code postal : 04070 Departement : ALPES-DE-HAUTE-PROVENCE
Code postal : 05061 Departement : HAUTES-ALPES
Code postal : 06088 Departement : ALPES-MARITIMES
Code postal : 07186 Departement : ARDECHE
Code postal : 08105 Departement : ARDENNES
Code postal : 09122 Departement : ARIEGE
Code postal : 10387 Departement : AUBE
Code postal : 11069 Departement : AUDE
Code postal : 12202 Departement : AVEYRON
Code postal : 13055 Departement : BOUCHES-DU-RHONE
Code postal : 14118 Departement : CALVADOS
Code postal : 15014 Departement : CANTAL
Code postal : 16015 Departement : CHARENTE
Code postal : 17300 Departement : CHARENTE-MARITIME
Code postal : 18033 Departement : CHER
Code postal : 19272 Departement : CORREZE
Code postal : 2A004 Departement : CORSE-DU-SUD
Code postal : 2B033 Departement : HAUTE-CORSE
Code postal : 21231 Departement : COTE-D'OR
Code postal : 22278 Departement : COTES-D'ARMOR
Code postal : 23096 Departement : CREUSE
Code postal : 24322 Departement : DORDOGNE
Code postal : 25056 Departement : DOUBS
Code postal : 26362 Departement : DROME
Code postal : 27229 Departement : EURE
Code postal : 28085 Departement : EURE-ET-LOIR
Code postal : 29232 Departement : FINISTERE
Code postal : 30189 Departement : GARD
Code postal : 31555 Departement : HAUTE-GARONNE
Code postal : 32013 Departement : GERS
Code postal : 33063 Departement : GIRONDE
Code postal : 34172 Departement : HERAULT
Code postal : 35238 Departement : ILLE-ET-VILAINE
Code postal : 36044 Departement : INDRE
Code postal : 37261 Departement : INDRE-ET-LOIRE
Code postal : 38185 Departement : ISERE
Code postal : 39300 Departement : JURA
Code postal : 40192 Departement : LANDES
Code postal : 41018 Departement : LOIR-ET-CHER
Code postal : 42218 Departement : LOIRE
Code postal : 43157 Departement : HAUTE-LOIRE
Code postal : 44109 Departement : LOIRE-ATLANTIQUE
Code postal : 45234 Departement : LOIRET
Code postal : 46042 Departement : LOT
Code postal : 47001 Departement : LOT-ET-GARONNE
Code postal : 48095 Departement : LOZERE
Code postal : 49007 Departement : MAINE-ET-LOIRE
Code postal : 50502 Departement : MANCHE
Code postal : 51108 Departement : MARNE
Code postal : 52121 Departement : HAUTE-MARNE
Code postal : 53130 Departement : MAYENNE
Code postal : 54395 Departement : MEURTHE-ET-MOSELLE
Code postal : 55029 Departement : MEUSE
Code postal : 56260 Departement : MORBIHAN
Code postal : 57463 Departement : MOSELLE
Code postal : 58194 Departement : NIEVRE
Code postal : 59350 Departement : NORD
Code postal : 60057 Departement : OISE
Code postal : 61001 Departement : ORNE
Code postal : 62041 Departement : PAS-DE-CALAIS
Code postal : 63113 Departement : PUY-DE-DOME
Code postal : 64445 Departement : PYRENEES-ATLANTIQUES
Code postal : 65440 Departement : HAUTES-PYRENEES
Code postal : 66136 Departement : PYRENEES-ORIENTALES
Code postal : 67482 Departement : BAS-RHIN
Code postal : 68066 Departement : HAUT-RHIN
Code postal : 69123 Departement : RHONE
Code postal : 70550 Departement : HAUTE-SAONE
Code postal : 71270 Departement : SAONE-ET-LOIRE
Code postal : 72181 Departement : SARTHE
Code postal : 73065 Departement : SAVOIE
Code postal : 74010 Departement : HAUTE-SAVOIE
Code postal : 75056 Departement : PARIS
Code postal : 76540 Departement : SEINE-MARITIME
Code postal : 77288 Departement : SEINE-ET-MARNE
Code postal : 78646 Departement : YVELINES
Code postal : 79191 Departement : DEUX-SEVRES
Code postal : 80021 Departement : SOMME
Code postal : 81004 Departement : TARN
Code postal : 82121 Departement : TARN-ET-GARONNE
Code postal : 83137 Departement : VAR
Code postal : 84007 Departement : VAUCLUSE
Code postal : 85191 Departement : VENDEE
Code postal : 86194 Departement : VIENNE
Code postal : 87085 Departement : HAUTE-VIENNE
Code postal : 88160 Departement : VOSGES
Code postal : 89024 Departement : YONNE
Code postal : 90010 Departement : TERRITOIRE DE BELFORT
Code postal : 91228 Departement : ESSONNE
Code postal : 92050 Departement : HAUTS-DE-SEINE
Code postal : 93008 Departement : SEINE-SAINT-DENIS
Code postal : 94028 Departement : VAL-DE-MARNE
Code postal : 95500 Departement : VAL-D'OISE
Code postal : 97105 Departement : GUADELOUPE
Code postal : 97209 Departement : MARTINIQUE
Code postal : 97302 Departement : GUYANE
Code postal : 97411 Departement : LA REUNION
Code postal : 97608 Departement : MAYOTTE
---------------
Fin de la liste
---------------
$
Extrait de Wikipédia :
Awk est le plus souvent utilisé pour la production de fichiers plats aux spécifications particulières (échanges entre différents systèmes d'informations hétérogènes). Il est aussi utilisé comme "parser" de fichiers XML ou de fichiers textes pour générer des commandes SQL à partir des données extraites. Il peut être utilisé aussi pour des opérations de calculs complexes et mise en forme de données brutes pour faire des tableaux statistiques.
On distingue awk, la commande originale, du new awk (nawk), arrivée un peu plus tard sur le marché. Les implémentations GNU de awk, sont en fait des new awk. On trouve en général la commande awk dans /usr/bin sous Unix. Certains systèmes GNU/Linux le mettent dans /bin. En général, elle est dans la variable d'environnement PATH. Cependant, on peut faire des scripts en awk et le shebang (#!/usr/bin/awk -f) devient faux. Le script est donc inutilisable si le binaire n’est pas là où on l’attend.
Il agit comme un filtre programmable prenant une série de lignes en entrée (sous forme de fichiers ou directement via l'entrée standard) et écrivant sur la sortie standard, qui peut être redirigée vers un autre fichier ou programme. Un programme Awk est composé de trois blocs distincts utilisables ou non pour le traitement d'un fichier (prétraitement, traitement, posttraitement). Awk lit sur l'entrée ligne par ligne, puis sélectionne (ou non) les lignes à traiter par des expressions rationnelles (et éventuellement des numéros de lignes). Une fois la ligne sélectionnée, elle est découpée en champs selon un séparateur d'entrée indiqué dans le programme awk par le symbole FS (qui par défaut correspond au caractère espace ou tabulation). Puis les différents champs sont disponibles dans des variables : $1 (premier champ), $2 (deuxième champ), $3 (troisième champ), ..., $NF (dernier champ).
« awk » est aussi l'extension de nom de fichier utilisée pour les scripts écrits dans ce langage.
awk [-F] '{action-awk}' [ fichier1 fichier2 ..... fichiern ]
awk [-F] -f script-awk [ fichier1 fichier2 ..... fichiern ]
La commande awk prend en argument la liste des fichiers à traiter. En l'absence de noms de fichiers sur la ligne de commande, awk travaille sur les données arrivant sur son entrée standard. Cette commande peut donc être placée derrière un tube de communication.
L'option "-F" permet d'initialiser, si besoin, la variable "FS" (Field Separator) correspondant au caractère séparateur de champ.
Le tableau suivant présente les principales variables internes du langage awk présentes en mémoire dès le lancement de la commande. La valeur de ces variables peut éventuellement être modifiée en fonction de la structure des données à traiter.
Nom de la variable | Valeur par défaut | Rôle de la variable |
---|---|---|
RS | Newline (\n) | Record Separator : Caractère séparateur d'enregistrement (lignes). |
FS | Suite d'espaces et/ou de tabulations | Field Separator : Caractères séparateurs de champs. |
OFS | Espace | Output Field Separator : Séparateur de champ utilisé pour l'affichage. |
ORS | Newline (\n) | Output Record Separator : Caractère séparateur d'enregistrement en sortie. |
ARGV | - | Tableau initialisé avec les arguments de la ligne de commande (options et nom du script awk exclus). |
ARGC | - | Nombre d'éléments contenus dans le tableau ARGV. |
ENVIRON | Variables d'environnement exportées par le shell. | Tableau contenant les variables d'environnement exportées par le shell. |
CONVFMT | %.6g | Format de conversion des nombres en String. |
OFMT | %.6g | Format de sortie des nombres. |
SUBSEP | \034 | Caractère de séparation pour les routines internes des tableaux. |
Par défaut, un enregistrement correspond donc à une ligne (suite de caractères terminée par "\n").
Lorsque la variable FS est initialisée avec un minimum de 2 caractères, cette valeur est interprétée comme une expression régulière.
Les enregistrements sont traités successivement. L'enregistrement courant est automatiquement découpé en champs et un certain nombre de variables internes awk sont initialisées. Le tableau suivant donne la liste des principales variables.
Nom de la variable | Valeur de la variable |
---|---|
$0 | Valeur de l'enregistrement courant |
NF | Number of Field : Nombre de champs de l'enregistrement courant. |
$1, $2, ... $NF | $1 contient la valeur du 1er champ, $2 la valeur du 2ème champ etc etc ... et $NF la valeur du dernier champ (NF est remplacé par sa valeur). |
NR | Number : Indice de l'enregistrement courant (NR vaut 1 quand la 1ère ligne est en cours de traitement, puis s'incrémente dès que awk change d'enregistrement). |
FNR | File Number : Indice de l'enregistrement courant relatif au fichier en cours de traitement. |
FILENAME | Nom du fichier en cours de traitement. |
RLENGTH | Longueur du string trouvé par la fonction match() |
RSTART | Première position du string trouvé par la fonction match() |
Contrairement aux variables du shell, le symbole "$" des variables awk $1, $2 etc etc... fait partie du nom des variables.
Premier exemple :
Ici, awk travaille sur le résultat de la commande ps -ef. La partie en rouge représente l'action que awk doit exécuter sur chaque ligne. Les simples quotes sont indispensables pour empêcher le shell d'interpréter les caractères destinés à la commande awk. Les instructions doivent être placées entre accolades. La fonction intégrée print va afficher à l'écran les champs 1 et 8 de chaque ligne.
$ ps -ef | awk '{print $1,$8}'
UID CMD
root init
...
www-data /usr/sbin/apache2
www-data /usr/sbin/apache2
root vzctl:
root -bash
postfix pickup
root ps
root awk
root /usr/lib/postfix/master
postfix qmgr
$
Deuxième exemple :
La fonction print peut également recevoir des chaines de caractères en argument.
$ ps -ef | awk '{print "User : " , $1, "\tCommande : " , $8}'
User : UID Commande : CMD
User : root Commande : init
User : root Commande : [kthreadd/113]
User : root Commande : [khelper/113]
User : root Commande : [init-logger]
...
User : root Commande : vzctl:
User : root Commande : -bash
User : root Commande : ps
User : root Commande : awk
User : root Commande : /usr/lib/postfix/master
$
\t représente le caractère tabulation.
Troisième exemple :
Modification du séparateur de champ "FS" grâce à l'option "-F"
$ cat /etc/passwd | awk -F : '{print $1,$7}'
root /bin/bash
...
nobody /bin/sh
libuuid /bin/sh
postfix /bin/false
sshd /usr/sbin/nologin
mysql /bin/false
$
Quatrième exemple :
$ cat /etc/passwd | awk -F : '{print "User : " , $1 , "\tShell : " , $7}'
User : root Shell : /bin/bash
User : daemon Shell : /bin/sh
User : bin Shell : /bin/sh
User : sys Shell : /bin/sh
User : sync Shell : /bin/sync
User : games Shell : /bin/sh
User : man Shell : /bin/sh
User : lp Shell : /bin/sh
User : mail Shell : /bin/sh
User : news Shell : /bin/sh
User : uucp Shell : /bin/sh
User : proxy Shell : /bin/sh
User : www-data Shell : /bin/sh
User : backup Shell : /bin/sh
User : list Shell : /bin/sh
User : irc Shell : /bin/sh
User : gnats Shell : /bin/sh
User : nobody Shell : /bin/sh
User : libuuid Shell : /bin/sh
User : postfix Shell : /bin/false
User : sshd Shell : /usr/sbin/nologin
User : mysql Shell : /bin/false
$
Si la fonction print ne reçoit pas d'argument, elle affiche $0.
$ cat /etc/passwd | awk -F : '{print}'
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
lp:x:7:7:lp:/var/spool/lpd:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh
proxy:x:13:13:proxy:/bin:/bin/sh
www-data:x:33:33:www-data:/var/www:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/sh
list:x:38:38:Mailing List Manager:/var/list:/bin/sh
irc:x:39:39:ircd:/var/run/ircd:/bin/sh
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh
nobody:x:65534:65534:nobody:/nonexistent:/bin/sh
libuuid:x:100:101::/var/lib/libuuid:/bin/sh
postfix:x:101:104::/var/spool/postfix:/bin/false
sshd:x:102:65534::/var/run/sshd:/usr/sbin/nologin
mysql:x:103:108:MySQL Server,,,:/var/lib/mysql:/bin/false
$
Il est possible de sélectionner les enregistrements sur lesquels l'action doit être exécutée.
Syntaxe :
awk [-F] 'critère {action-awk}' [fichier1 fichier2 ... fichiern]
Le critère de sélection peut s'exprimer de différentes manières.
Les enregistrements à traiter peuvent être sélectionnés en utilisant les expressions régulières étendues (ERe).
Attention, pour utiliser les quantificateurs {x,y} d'une ERe, il faut utiliser awk avec l'option --posix
Premier exemple :
Afficher les lignes du fichier /etc/passwd contenant /bin/false
$ awk -F':' '/\/bin\/false/ {print $0}' /etc/passwd
postfix:x:101:104::/var/spool/postfix:/bin/false
mysql:x:103:108:MySQL Server,,,:/var/lib/mysql:/bin/false
$
Par défaut, le critère est mis en correspondance avec $0.
Il est possible de mettre un champ particulier en correspondance avec une expression régulière. Dans ce cas, il faut utiliser l'opérateur de concordance "~" ou de non-concordance "!~".
Deuxième exemple :
Afficher les lignes du fichier /etc/passwd dont le 6ème champ commence par /usr.
$ awk -F':' '$6 ~ /^\/usr/ {print $0}' /etc/passwd
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
games:x:5:60:games:/usr/games:/bin/sh
$
Et à l'inverse
$ awk -F':' '$6 !~ /^\/usr/ {print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:2:2:bin:/bin:/bin/sh
...
postfix:x:101:104::/var/spool/postfix:/bin/false
sshd:x:102:65534::/var/run/sshd:/usr/sbin/nologin
mysql:x:103:108:MySQL Server,,,:/var/lib/mysql:/bin/false
$
Le critère peut être une expression d'opérateurs et renvoyant la valeur de vérité vrai ou faux.
Opérateurs de tests courants
Opérateur | Signification |
---|---|
< | Inférieur |
> | Supérieur |
<= | Inférieur ou égal |
>= | Supérieur ou égal |
== | Test d'égalité |
!= | Test d'inégalité |
~ | Correspondance avec une expression régulière |
!~ | Non-correspondance avec une expression régulière |
! | Négation |
&& | Et logique |
|| | Ou logique |
(expression) | Regroupement |
Exemple :
Afficher les champs 1 et 7 de la ligne 4 et 8 du fichier /etc/passwd
$ awk -F':' 'NR == 4 || NR == 8 {print $1,"==>",$7}' /etc/passwd
sys ==> /bin/sh
lp ==> /bin/sh
$
Le chiffre 0 et la chaîne vide sont des valeurs fausses. Toute autre valeur est vraie.
Afficher uniquement les lignes impaires du fichier /etc/passwd.
Le résultat de l'opération NR%2 représentant le reste de la division par 2 du numéro de ligne en cours de traitement, cela permet d'afficher uniquement les lignes impaires du fichier car seulement les nombres impairs renvoient un reste de division différent de 0 (donc vrai). Equivalent à NR%2!=0
$ nl /etc/passwd
1 root:x:0:0:root:/root:/bin/bash
2 daemon:x:1:1:daemon:/usr/sbin:/bin/sh
3 bin:x:2:2:bin:/bin:/bin/sh
4 sys:x:3:3:sys:/dev:/bin/sh
5 sync:x:4:65534:sync:/bin:/bin/sync
6 games:x:5:60:games:/usr/games:/bin/sh
7 man:x:6:12:man:/var/cache/man:/bin/sh
8 lp:x:7:7:lp:/var/spool/lpd:/bin/sh
9 mail:x:8:8:mail:/var/mail:/bin/sh
10 news:x:9:9:news:/var/spool/news:/bin/sh
11 uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh
12 proxy:x:13:13:proxy:/bin:/bin/sh
13 www-data:x:33:33:www-data:/var/www:/bin/sh
14 backup:x:34:34:backup:/var/backups:/bin/sh
15 list:x:38:38:Mailing List Manager:/var/list:/bin/sh
16 irc:x:39:39:ircd:/var/run/ircd:/bin/sh
17 gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh
18 nobody:x:65534:65534:nobody:/nonexistent:/bin/sh
19 libuuid:x:100:101::/var/lib/libuuid:/bin/sh
20 postfix:x:101:104::/var/spool/postfix:/bin/false
21 sshd:x:102:65534::/var/run/sshd:/usr/sbin/nologin
22 mysql:x:103:108:MySQL Server,,,:/var/lib/mysql:/bin/false
$
$ awk -F':' 'NR%2 {print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:2:2:bin:/bin:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync
man:x:6:12:man:/var/cache/man:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh
www-data:x:33:33:www-data:/var/www:/bin/sh
list:x:38:38:Mailing List Manager:/var/list:/bin/sh
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh
libuuid:x:100:101::/var/lib/libuuid:/bin/sh
sshd:x:102:65534::/var/run/sshd:/usr/sbin/nologin
$
A l'inverse, afficher uniquement les lignes paires.
$ awk -F':' 'NR%2==0 {print $0}' /etc/passwd
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
games:x:5:60:games:/usr/games:/bin/sh
lp:x:7:7:lp:/var/spool/lpd:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
proxy:x:13:13:proxy:/bin:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/sh
irc:x:39:39:ircd:/var/run/ircd:/bin/sh
nobody:x:65534:65534:nobody:/nonexistent:/bin/sh
postfix:x:101:104::/var/spool/postfix:/bin/false
mysql:x:103:108:MySQL Server,,,:/var/lib/mysql:/bin/false
$
Afficher les champs 1 et 7 de la ligne 4 à 8 du fichier /etc/passwd
$ awk -F':' 'NR == 4 , NR == 8 {print $1,"==>",$7}' /etc/passwd
sys ==> /bin/sh
sync ==> /bin/sync
games ==> /bin/sh
man ==> /bin/sh
lp ==> /bin/sh
$
Lorsqu'il y a un certain nombre d'actions à réaliser sur les données, il est plus confortable d'écrire un script awk. Un script awk peut contenir une section BEGIN, une section END, et 0 à x sections intermédiaires. Toute section est facultative.
BEGIN
La section BEGIN est exécutée avant le traitement du premier enregistrement des données. Elle est utilisée essentiellement pour initialiser le contexte d'exécution.
Sections intermédiaires
Il peut y avoir plusieurs sections intermédiaires qui seront exécutées sur chaque enregistrement.
END
La section END est exécutée après le traitement du dernier enregistrement des données. Elle est utilisée pour exploiter les résultats issus du traitement des données.
Commentaires
Un commentaire commence par le caractère "#" et se termine au caractère "\n" (fin de la ligne).
Variables
Des variables personnelles peuvent être créées. Une variable est définie dès qu'elle est initialisée et n'a pas besoin d'être typée. L'utilisation d'une variable qui n'a jamais été définie a pour valeur 0 dans un contexte numérique et chaine vide dans un contexte de chaine.
Exemple :
$ nl script1.awk
1 # Section BEGIN
2 BEGIN {
3 print "Section BEGIN"
4 nb_0=0
5 nb_1=0
6 nb_2=0
7 nb_3=0
8 nb_4=0
9 nb_5=0
10 nb_6=0
11 nb_7=0
12 nb_8=0
13 nb_9=0
14 }
15 # Section intermediaire
16 # Traitement des departements commancant par 0
17 $2 ~ /^0/ {
18 print "Departement commancant par 0 ==> CP : " , $3 , "DEPT : " , $5
19 nb_0+=1
20 }
21 # Section intermediaire
22 # Traitement des departements commancant par 1
23 $2 ~ /^1/ {
24 print "Departement commancant par 1 ==> CP : " , $3 , "DEPT : " , $5
25 nb_1+=1
26 }
27 # Section intermediaire
28 # Traitement des departements commancant par 2
29 $2 ~ /^2/ {
30 print "Departement commancant par 2 ==> CP : " , $3 , "DEPT : " , $5
31 nb_2+=1
32 }
33 # Section intermediaire
34 # Traitement des departements commancant par 3
35 $2 ~ /^3/ {
36 print "Departement commancant par 3 ==> CP : " , $3 , "DEPT : " , $5
37 nb_3+=1
38 }
39 # Section intermediaire
40 # Traitement des departements commancant par 4
41 $2 ~ /^4/ {
42 print "Departement commancant par 4 ==> CP : " , $3 , "DEPT : " , $5
43 nb_4+=1
44 }
45 # Section intermediaire
46 # Traitement des departements commancant par 5
47 $2 ~ /^5/ {
48 print "Departement commancant par 5 ==> CP : " , $3 , "DEPT : " , $5
49 nb_5+=1
50 }
51 # Section intermediaire
52 # Traitement des departements commancant par 6
53 $2 ~ /^6/ {
54 print "Departement commancant par 6 ==> CP : " , $3 , "DEPT : " , $5
55 nb_6+=1
56 }
57 # Section intermediaire
58 # Traitement des departements commancant par 7
59 $2 ~ /^7/ {
60 print "Departement commancant par 7 ==> CP : " , $3 , "DEPT : " , $5
61 nb_7+=1
62 }
63 # Section intermediaire
64 # Traitement des departements commancant par 8
65 $2 ~ /^8/ {
66 print "Departement commancant par 8 ==> CP : " , $3 , "DEPT : " , $5
67 nb_8+=1
68 }
69 # Section intermediaire
70 # Traitement des departements commancant par 9
71 $2 ~ /^9/ {
72 print "Departement commancant par 9 ==> CP : " , $3 , "DEPT : " , $5
73 nb_9+=1
74 }
75 # Section END
76 END {
77 print "Section END"
78 print "Nombre total de lignes : " , NR
79 print "Nombre de departements commencant par 0 : " , nb_0
80 print "Nombre de departements commencant par 1 : " , nb_1
81 print "Nombre de departements commencant par 2 : " , nb_2
82 print "Nombre de departements commencant par 3 : " , nb_3
83 print "Nombre de departements commencant par 4 : " , nb_4
84 print "Nombre de departements commencant par 5 : " , nb_5
85 print "Nombre de departements commencant par 6 : " , nb_6
86 print "Nombre de departements commencant par 7 : " , nb_7
87 print "Nombre de departements commencant par 8 : " , nb_8
88 print "Nombre de departements commencant par 9 : " , nb_9
89 }
$
Section BEGIN
Initialisation des variables personnelles servant de compteur.
Sections intermédiaires
Exécution des traitements spécifiques en fonction du début du numéro des départements.
Section END
Affichage du nombre total de lignes traitées et du nombre de départements regroupés par dizaine du numéro de départements.
Exécution du script
$ awk -f script1.awk depts2012.txt
Section BEGIN
Departement commancant par 0 ==> CP : 01053 DEPT : AIN
Departement commancant par 0 ==> CP : 02408 DEPT : AISNE
Departement commancant par 0 ==> CP : 03190 DEPT : ALLIER
Departement commancant par 0 ==> CP : 04070 DEPT : ALPES-DE-HAUTE-PROVENCE
Departement commancant par 0 ==> CP : 05061 DEPT : HAUTES-ALPES
Departement commancant par 0 ==> CP : 06088 DEPT : ALPES-MARITIMES
Departement commancant par 0 ==> CP : 07186 DEPT : ARDECHE
Departement commancant par 0 ==> CP : 08105 DEPT : ARDENNES
Departement commancant par 0 ==> CP : 09122 DEPT : ARIEGE
Departement commancant par 1 ==> CP : 10387 DEPT : AUBE
Departement commancant par 1 ==> CP : 11069 DEPT : AUDE
Departement commancant par 1 ==> CP : 12202 DEPT : AVEYRON
Departement commancant par 1 ==> CP : 13055 DEPT : BOUCHES-DU-RHONE
Departement commancant par 1 ==> CP : 14118 DEPT : CALVADOS
Departement commancant par 1 ==> CP : 15014 DEPT : CANTAL
Departement commancant par 1 ==> CP : 16015 DEPT : CHARENTE
Departement commancant par 1 ==> CP : 17300 DEPT : CHARENTE-MARITIME
Departement commancant par 1 ==> CP : 18033 DEPT : CHER
Departement commancant par 1 ==> CP : 19272 DEPT : CORREZE
Departement commancant par 2 ==> CP : 2A004 DEPT : CORSE-DU-SUD
Departement commancant par 2 ==> CP : 2B033 DEPT : HAUTE-CORSE
Departement commancant par 2 ==> CP : 21231 DEPT : COTE-D'OR
Departement commancant par 2 ==> CP : 22278 DEPT : COTES-D'ARMOR
Departement commancant par 2 ==> CP : 23096 DEPT : CREUSE
Departement commancant par 2 ==> CP : 24322 DEPT : DORDOGNE
Departement commancant par 2 ==> CP : 25056 DEPT : DOUBS
Departement commancant par 2 ==> CP : 26362 DEPT : DROME
Departement commancant par 2 ==> CP : 27229 DEPT : EURE
Departement commancant par 2 ==> CP : 28085 DEPT : EURE-ET-LOIR
Departement commancant par 2 ==> CP : 29232 DEPT : FINISTERE
Departement commancant par 3 ==> CP : 30189 DEPT : GARD
Departement commancant par 3 ==> CP : 31555 DEPT : HAUTE-GARONNE
Departement commancant par 3 ==> CP : 32013 DEPT : GERS
Departement commancant par 3 ==> CP : 33063 DEPT : GIRONDE
Departement commancant par 3 ==> CP : 34172 DEPT : HERAULT
Departement commancant par 3 ==> CP : 35238 DEPT : ILLE-ET-VILAINE
Departement commancant par 3 ==> CP : 36044 DEPT : INDRE
Departement commancant par 3 ==> CP : 37261 DEPT : INDRE-ET-LOIRE
Departement commancant par 3 ==> CP : 38185 DEPT : ISERE
Departement commancant par 3 ==> CP : 39300 DEPT : JURA
Departement commancant par 4 ==> CP : 40192 DEPT : LANDES
Departement commancant par 4 ==> CP : 41018 DEPT : LOIR-ET-CHER
Departement commancant par 4 ==> CP : 42218 DEPT : LOIRE
Departement commancant par 4 ==> CP : 43157 DEPT : HAUTE-LOIRE
Departement commancant par 4 ==> CP : 44109 DEPT : LOIRE-ATLANTIQUE
Departement commancant par 4 ==> CP : 45234 DEPT : LOIRET
Departement commancant par 4 ==> CP : 46042 DEPT : LOT
Departement commancant par 4 ==> CP : 47001 DEPT : LOT-ET-GARONNE
Departement commancant par 4 ==> CP : 48095 DEPT : LOZERE
Departement commancant par 4 ==> CP : 49007 DEPT : MAINE-ET-LOIRE
Departement commancant par 5 ==> CP : 50502 DEPT : MANCHE
Departement commancant par 5 ==> CP : 51108 DEPT : MARNE
Departement commancant par 5 ==> CP : 52121 DEPT : HAUTE-MARNE
Departement commancant par 5 ==> CP : 53130 DEPT : MAYENNE
Departement commancant par 5 ==> CP : 54395 DEPT : MEURTHE-ET-MOSELLE
Departement commancant par 5 ==> CP : 55029 DEPT : MEUSE
Departement commancant par 5 ==> CP : 56260 DEPT : MORBIHAN
Departement commancant par 5 ==> CP : 57463 DEPT : MOSELLE
Departement commancant par 5 ==> CP : 58194 DEPT : NIEVRE
Departement commancant par 5 ==> CP : 59350 DEPT : NORD
Departement commancant par 6 ==> CP : 60057 DEPT : OISE
Departement commancant par 6 ==> CP : 61001 DEPT : ORNE
Departement commancant par 6 ==> CP : 62041 DEPT : PAS-DE-CALAIS
Departement commancant par 6 ==> CP : 63113 DEPT : PUY-DE-DOME
Departement commancant par 6 ==> CP : 64445 DEPT : PYRENEES-ATLANTIQUES
Departement commancant par 6 ==> CP : 65440 DEPT : HAUTES-PYRENEES
Departement commancant par 6 ==> CP : 66136 DEPT : PYRENEES-ORIENTALES
Departement commancant par 6 ==> CP : 67482 DEPT : BAS-RHIN
Departement commancant par 6 ==> CP : 68066 DEPT : HAUT-RHIN
Departement commancant par 6 ==> CP : 69123 DEPT : RHONE
Departement commancant par 7 ==> CP : 70550 DEPT : HAUTE-SAONE
Departement commancant par 7 ==> CP : 71270 DEPT : SAONE-ET-LOIRE
Departement commancant par 7 ==> CP : 72181 DEPT : SARTHE
Departement commancant par 7 ==> CP : 73065 DEPT : SAVOIE
Departement commancant par 7 ==> CP : 74010 DEPT : HAUTE-SAVOIE
Departement commancant par 7 ==> CP : 75056 DEPT : PARIS
Departement commancant par 7 ==> CP : 76540 DEPT : SEINE-MARITIME
Departement commancant par 7 ==> CP : 77288 DEPT : SEINE-ET-MARNE
Departement commancant par 7 ==> CP : 78646 DEPT : YVELINES
Departement commancant par 7 ==> CP : 79191 DEPT : DEUX-SEVRES
Departement commancant par 8 ==> CP : 80021 DEPT : SOMME
Departement commancant par 8 ==> CP : 81004 DEPT : TARN
Departement commancant par 8 ==> CP : 82121 DEPT : TARN-ET-GARONNE
Departement commancant par 8 ==> CP : 83137 DEPT : VAR
Departement commancant par 8 ==> CP : 84007 DEPT : VAUCLUSE
Departement commancant par 8 ==> CP : 85191 DEPT : VENDEE
Departement commancant par 8 ==> CP : 86194 DEPT : VIENNE
Departement commancant par 8 ==> CP : 87085 DEPT : HAUTE-VIENNE
Departement commancant par 8 ==> CP : 88160 DEPT : VOSGES
Departement commancant par 8 ==> CP : 89024 DEPT : YONNE
Departement commancant par 9 ==> CP : 90010 DEPT : TERRITOIRE
Departement commancant par 9 ==> CP : 91228 DEPT : ESSONNE
Departement commancant par 9 ==> CP : 92050 DEPT : HAUTS-DE-SEINE
Departement commancant par 9 ==> CP : 93008 DEPT : SEINE-SAINT-DENIS
Departement commancant par 9 ==> CP : 94028 DEPT : VAL-DE-MARNE
Departement commancant par 9 ==> CP : 95500 DEPT : VAL-D'OISE
Departement commancant par 9 ==> CP : 97105 DEPT : GUADELOUPE
Departement commancant par 9 ==> CP : 97209 DEPT : MARTINIQUE
Departement commancant par 9 ==> CP : 97302 DEPT : GUYANE
Departement commancant par 9 ==> CP : 97411 DEPT : LA
Departement commancant par 9 ==> CP : 97608 DEPT : MAYOTTE
Section END
Nombre total de lignes : 102
Nombre de departements commencant par 0 : 9
Nombre de departements commencant par 1 : 10
Nombre de departements commencant par 2 : 11
Nombre de departements commencant par 3 : 10
Nombre de departements commencant par 4 : 10
Nombre de departements commencant par 5 : 10
Nombre de departements commencant par 6 : 10
Nombre de departements commencant par 7 : 10
Nombre de departements commencant par 8 : 10
Nombre de departements commencant par 9 : 11
$
Liste des opérateurs disponible dans awk.
Opérateur | Arité | Signification |
---|---|---|
+ | Binaire | Addition |
- | Binaire | Soustraction |
* | Binaire | Multiplication |
/ | Binaire | Division |
% | Binaire | Modulo |
^ | Binaire | Exponentiation |
++ | Unaire | Incrémentation d'une variable d'une unité |
-- | Unaire | Décrémentation d'une variable d'une unité |
+= | Binaire | a+=b equivalent à a=a+b |
-= | Binaire | a-=b équivalent à a=a-b |
*= | Binaire | a*=b équivalent à a=a*b |
/= | Binaire | a/=b équivalent à a=a/b |
%= | Binaire | a%=b équivalent à a=a%b |
^= | Binaire | a^=b équivalent à a=a^b |
Opérateur | Arité | Signification |
---|---|---|
< | Binaire | Inférieur |
> | Binaire | Supérieur |
<= | Binaire | Inférieur ou égal |
>= | Binaire | Supérieur ou égal |
== | Binaire | Test d'égalité |
!= | Binaire | Test d'inégalité |
~ | Binaire | Correspondance avec une ERe |
!~ | Binaire | Non correspondance avec une ERe |
Opérateur | Arité | Signification |
---|---|---|
! | Binaire | Négation |
&& | Binaire | ET logique |
|| | Binaire | OU logique |
Opérateur | Arité | Signification |
---|---|---|
= | Binaire | Affectation |
e1 ? e2 : e3 | Ternaire | Le résultat est égal à e2 si e1 est vrai, égal à e3 si e1 est faux |
e1 e2 | Binaire | Concaténation de e1 et e2 |
awk propose la fonction intégrée printf similaire à celle du langage C. Elle permet de formater les affichages.
printf ("chaine",field1,field2,field3...fieldx)
chaine représente la chaine affichée à l'écran. Elle peut contenir des formats qui seront substitués par la valeur des expressions citées à la suite. Il doit y avoir autant de formats que d'expressions.
Formats souvent utilisés
Format | Signification |
---|---|
%20s | Affichage d'une chaine (string) sur 20 caractères (cadrage à droite par défaut) |
%-20s | Affichage d'une chaine (string) sur 20 caractères avec cadrage à gauche |
%3d | Affichage d'un entier/décimal sur 3 chiffres (cadrage à droite) |
%03d | Affichage d'un entier/décimal sur 3 chiffres (cadrage à droite) complété par des 0 à gauche |
%-3d | Affichage d'un entier/décimal sur 3 chiffres (cadrage à gauche) |
%+3d | Affichage d'un entier/décimal sur 3 chiffres (cadrage à droite) avec affichage systématique du signe (un nombre négatif est toujours affiché avec son signe) |
%10.2f | Affichage d'un nombre flottant sur 10 chiffres dont 2 décimales. (cadrage à droite) |
%+010.2f | Affichage d'un nombre flottant sur 10 chiffres dont 2 décimales, cadrage à droite, affichage systématique du signe, complétion par des 0 à gauche. |
Exemple :
$ date | awk '{printf "%10s\n%-10s\n%d\n%15d\n%015d\n%-10d\n%+10d\n%10.2f\n%+010.2f\n" , $1 , $1 , $4 , $4 , $4 , $4 , $4 , 5.2 , 5.2}'
mer. # %10s
mer. # %-10s
2012 # %d
2012 # %15d
000000000002012 # %015d
2012 # %-10d
+2012 # %+10d
5.20 # %10.2f
+000005.20 # %+010.2f
$
Il est possible de rediriger les sorties du script vers un fichier ou vers une commande du système.
Syntaxe
instruction > "fichier" | Au premier appel, le fichier est ouvert en mode "écrasement", puis écriture. Les écritures suivantes se font en mode "ajout" |
instruction >> "fichier" | Au premier appel, le fichier est ouvert en mode "ajout", puis écriture. Les écritures suivantes se font également en mode "ajout" |
print[f] "..." | "commande" | Le résultat de la fonction print/printf est transmise sur l'entrée standard de la commande système par l'intermédiaire d'un tube (pipe) |
Exemple 1
Ouverture en mode "écrasement"
$ nl script2.awk
1 BEGIN {
2 fichier = "/root/fichier1.txt"
3 print "Ligne 1" > fichier
4 print "Ligne 2" > fichier
5 print "Ligne 3" > fichier
6 close(fichier)
7 }
$ uptime > /root/fichier1.txt
$ cat /root/fichier1.txt
13:47:18 up 7 days, 5:28, 0 users, load average: 0.00, 0.00, 0.00
$ awk -f script2.awk
$ cat /root/fichier1.txt
Ligne 1
Ligne 2
Ligne 3
$
Exemple 2
Ouverture en mode "ajout"
$ nl script3.awk
1 BEGIN {
2 fichier = "/root/fichier1.txt"
3 print "Ligne 1" >> fichier
4 print "Ligne 2" > fichier
5 print "Ligne 3" > fichier
6 close(fichier)
7 }
$ uptime > /root/fichier1.txt
$ cat /root/fichier1.txt
13:50:40 up 7 days, 5:31, 0 users, load average: 0.00, 0.00, 0.00
$ awk -f script3.awk
$ cat /root/fichier1.txt
13:50:40 up 7 days, 5:31, 0 users, load average: 0.00, 0.00, 0.00
Ligne 1
Ligne 2
Ligne 3
$
Exemple 3
Ecriture dans un tube. Trier les lignes par users croissants.
La commande sort est exécutée une seule fois puis fermée dans la section END.
$ nl /etc/passwd
1 root:x:0:0:root:/root:/bin/bash
2 daemon:x:1:1:daemon:/usr/sbin:/bin/sh
3 bin:x:2:2:bin:/bin:/bin/sh
4 sys:x:3:3:sys:/dev:/bin/sh
5 sync:x:4:65534:sync:/bin:/bin/sync
6 games:x:5:60:games:/usr/games:/bin/sh
7 man:x:6:12:man:/var/cache/man:/bin/sh
8 lp:x:7:7:lp:/var/spool/lpd:/bin/sh
9 mail:x:8:8:mail:/var/mail:/bin/sh
10 news:x:9:9:news:/var/spool/news:/bin/sh
11 uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh
12 proxy:x:13:13:proxy:/bin:/bin/sh
13 www-data:x:33:33:www-data:/var/www:/bin/sh
14 backup:x:34:34:backup:/var/backups:/bin/sh
15 list:x:38:38:Mailing List Manager:/var/list:/bin/sh
16 irc:x:39:39:ircd:/var/run/ircd:/bin/sh
17 gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh
18 nobody:x:65534:65534:nobody:/nonexistent:/bin/sh
19 libuuid:x:100:101::/var/lib/libuuid:/bin/sh
20 postfix:x:101:104::/var/spool/postfix:/bin/false
21 sshd:x:102:65534::/var/run/sshd:/usr/sbin/nologin
22 mysql:x:103:108:MySQL Server,,,:/var/lib/mysql:/bin/false
$ awk -F':' '{print $0 | "sort"} END {close("sort")}' /etc/passwd
backup:x:34:34:backup:/var/backups:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
games:x:5:60:games:/usr/games:/bin/sh
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh
irc:x:39:39:ircd:/var/run/ircd:/bin/sh
libuuid:x:100:101::/var/lib/libuuid:/bin/sh
list:x:38:38:Mailing List Manager:/var/list:/bin/sh
lp:x:7:7:lp:/var/spool/lpd:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
mysql:x:103:108:MySQL Server,,,:/var/lib/mysql:/bin/false
news:x:9:9:news:/var/spool/news:/bin/sh
nobody:x:65534:65534:nobody:/nonexistent:/bin/sh
postfix:x:101:104::/var/spool/postfix:/bin/false
proxy:x:13:13:proxy:/bin:/bin/sh
root:x:0:0:root:/root:/bin/bash
sshd:x:102:65534::/var/run/sshd:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
sys:x:3:3:sys:/dev:/bin/sh
uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh
www-data:x:33:33:www-data:/var/www:/bin/sh
$
L'instruction next interrompt le traitement de la ligne courante et déclenche la lecture de la ligne suivante.
Exemple
Dans le script suivant, les instruction next permettent d'accélérer l'exécution en évitant le traitement de la ligne courante dans les sections suivantes celle où la ligne a été traitée.
$ nl script4.awk
1 # Section BEGIN
2 BEGIN {
3 nb_0=0
4 nb_1=0
5 nb_2=0
6 nb_3=0
7 nb_4=0
8 nb_5=0
9 nb_6=0
10 nb_7=0
11 nb_8=0
12 nb_9=0
13 }
14 # Section intermediaire
15 # Traitement des departements commancant par 0
16 $2 ~ /^0/ {
17 print "Departement commancant par 0 ==> CP : " , $3 , "DEPT : " , $5
18 nb_0+=1
19 next
20 }
21 # Section intermediaire
22 # Traitement des departements commancant par 1
23 $2 ~ /^1/ {
24 print "Departement commancant par 1 ==> CP : " , $3 , "DEPT : " , $5
25 nb_1+=1
26 next
27 }
28 # Section intermediaire
29 # Traitement des departements commancant par 2
30 $2 ~ /^2/ {
31 print "Departement commancant par 2 ==> CP : " , $3 , "DEPT : " , $5
32 nb_2+=1
33 next
34 }
35 # Section intermediaire
36 # Traitement des departements commancant par 3
37 $2 ~ /^3/ {
38 print "Departement commancant par 3 ==> CP : " , $3 , "DEPT : " , $5
39 nb_3+=1
40 next
41 }
42 # Section intermediaire
43 # Traitement des departements commancant par 4
44 $2 ~ /^4/ {
45 print "Departement commancant par 4 ==> CP : " , $3 , "DEPT : " , $5
46 nb_4+=1
47 next
48 }
49 # Section intermediaire
50 # Traitement des departements commancant par 5
51 $2 ~ /^5/ {
52 print "Departement commancant par 5 ==> CP : " , $3 , "DEPT : " , $5
53 nb_5+=1
54 next
55 }
56 # Section intermediaire
57 # Traitement des departements commancant par 6
58 $2 ~ /^6/ {
59 print "Departement commancant par 6 ==> CP : " , $3 , "DEPT : " , $5
60 nb_6+=1
61 next
62 }
63 # Section intermediaire
64 # Traitement des departements commancant par 7
65 $2 ~ /^7/ {
66 print "Departement commancant par 7 ==> CP : " , $3 , "DEPT : " , $5
67 nb_7+=1
68 next
69 }
70 # Section intermediaire
71 # Traitement des departements commancant par 8
72 $2 ~ /^8/ {
73 print "Departement commancant par 8 ==> CP : " , $3 , "DEPT : " , $5
74 nb_8+=1
75 next
76 }
77 # Section intermediaire
78 # Traitement des departements commancant par 9
79 $2 ~ /^9/ {
80 print "Departement commancant par 9 ==> CP : " , $3 , "DEPT : " , $5
81 nb_9+=1
82 next
83 }
84 # Section END
85 END {
86 print "Nombre total de lignes : " , NR
87 print "Nombre de departements commencant par 0 : " , nb_0
88 print "Nombre de departements commencant par 1 : " , nb_1
89 print "Nombre de departements commencant par 2 : " , nb_2
90 print "Nombre de departements commencant par 3 : " , nb_3
91 print "Nombre de departements commencant par 4 : " , nb_4
92 print "Nombre de departements commencant par 5 : " , nb_5
93 print "Nombre de departements commencant par 6 : " , nb_6
94 print "Nombre de departements commencant par 7 : " , nb_7
95 print "Nombre de departements commencant par 8 : " , nb_8
96 print "Nombre de departements commencant par 9 : " , nb_9
97 }
$
$ awk -f script4.awk depts2012.txt
Departement commancant par 0 ==> CP : 01053 DEPT : AIN
Departement commancant par 0 ==> CP : 02408 DEPT : AISNE
Departement commancant par 0 ==> CP : 03190 DEPT : ALLIER
Departement commancant par 0 ==> CP : 04070 DEPT : ALPES-DE-HAUTE-PROVENCE
Departement commancant par 0 ==> CP : 05061 DEPT : HAUTES-ALPES
Departement commancant par 0 ==> CP : 06088 DEPT : ALPES-MARITIMES
Departement commancant par 0 ==> CP : 07186 DEPT : ARDECHE
Departement commancant par 0 ==> CP : 08105 DEPT : ARDENNES
Departement commancant par 0 ==> CP : 09122 DEPT : ARIEGE
Departement commancant par 1 ==> CP : 10387 DEPT : AUBE
Departement commancant par 1 ==> CP : 11069 DEPT : AUDE
Departement commancant par 1 ==> CP : 12202 DEPT : AVEYRON
Departement commancant par 1 ==> CP : 13055 DEPT : BOUCHES-DU-RHONE
Departement commancant par 1 ==> CP : 14118 DEPT : CALVADOS
Departement commancant par 1 ==> CP : 15014 DEPT : CANTAL
Departement commancant par 1 ==> CP : 16015 DEPT : CHARENTE
Departement commancant par 1 ==> CP : 17300 DEPT : CHARENTE-MARITIME
Departement commancant par 1 ==> CP : 18033 DEPT : CHER
Departement commancant par 1 ==> CP : 19272 DEPT : CORREZE
Departement commancant par 2 ==> CP : 2A004 DEPT : CORSE-DU-SUD
Departement commancant par 2 ==> CP : 2B033 DEPT : HAUTE-CORSE
Departement commancant par 2 ==> CP : 21231 DEPT : COTE-D'OR
Departement commancant par 2 ==> CP : 22278 DEPT : COTES-D'ARMOR
Departement commancant par 2 ==> CP : 23096 DEPT : CREUSE
Departement commancant par 2 ==> CP : 24322 DEPT : DORDOGNE
Departement commancant par 2 ==> CP : 25056 DEPT : DOUBS
Departement commancant par 2 ==> CP : 26362 DEPT : DROME
Departement commancant par 2 ==> CP : 27229 DEPT : EURE
Departement commancant par 2 ==> CP : 28085 DEPT : EURE-ET-LOIR
Departement commancant par 2 ==> CP : 29232 DEPT : FINISTERE
Departement commancant par 3 ==> CP : 30189 DEPT : GARD
Departement commancant par 3 ==> CP : 31555 DEPT : HAUTE-GARONNE
Departement commancant par 3 ==> CP : 32013 DEPT : GERS
Departement commancant par 3 ==> CP : 33063 DEPT : GIRONDE
Departement commancant par 3 ==> CP : 34172 DEPT : HERAULT
Departement commancant par 3 ==> CP : 35238 DEPT : ILLE-ET-VILAINE
Departement commancant par 3 ==> CP : 36044 DEPT : INDRE
Departement commancant par 3 ==> CP : 37261 DEPT : INDRE-ET-LOIRE
Departement commancant par 3 ==> CP : 38185 DEPT : ISERE
Departement commancant par 3 ==> CP : 39300 DEPT : JURA
Departement commancant par 4 ==> CP : 40192 DEPT : LANDES
Departement commancant par 4 ==> CP : 41018 DEPT : LOIR-ET-CHER
Departement commancant par 4 ==> CP : 42218 DEPT : LOIRE
Departement commancant par 4 ==> CP : 43157 DEPT : HAUTE-LOIRE
Departement commancant par 4 ==> CP : 44109 DEPT : LOIRE-ATLANTIQUE
Departement commancant par 4 ==> CP : 45234 DEPT : LOIRET
Departement commancant par 4 ==> CP : 46042 DEPT : LOT
Departement commancant par 4 ==> CP : 47001 DEPT : LOT-ET-GARONNE
Departement commancant par 4 ==> CP : 48095 DEPT : LOZERE
Departement commancant par 4 ==> CP : 49007 DEPT : MAINE-ET-LOIRE
Departement commancant par 5 ==> CP : 50502 DEPT : MANCHE
Departement commancant par 5 ==> CP : 51108 DEPT : MARNE
Departement commancant par 5 ==> CP : 52121 DEPT : HAUTE-MARNE
Departement commancant par 5 ==> CP : 53130 DEPT : MAYENNE
Departement commancant par 5 ==> CP : 54395 DEPT : MEURTHE-ET-MOSELLE
Departement commancant par 5 ==> CP : 55029 DEPT : MEUSE
Departement commancant par 5 ==> CP : 56260 DEPT : MORBIHAN
Departement commancant par 5 ==> CP : 57463 DEPT : MOSELLE
Departement commancant par 5 ==> CP : 58194 DEPT : NIEVRE
Departement commancant par 5 ==> CP : 59350 DEPT : NORD
Departement commancant par 6 ==> CP : 60057 DEPT : OISE
Departement commancant par 6 ==> CP : 61001 DEPT : ORNE
Departement commancant par 6 ==> CP : 62041 DEPT : PAS-DE-CALAIS
Departement commancant par 6 ==> CP : 63113 DEPT : PUY-DE-DOME
Departement commancant par 6 ==> CP : 64445 DEPT : PYRENEES-ATLANTIQUES
Departement commancant par 6 ==> CP : 65440 DEPT : HAUTES-PYRENEES
Departement commancant par 6 ==> CP : 66136 DEPT : PYRENEES-ORIENTALES
Departement commancant par 6 ==> CP : 67482 DEPT : BAS-RHIN
Departement commancant par 6 ==> CP : 68066 DEPT : HAUT-RHIN
Departement commancant par 6 ==> CP : 69123 DEPT : RHONE
Departement commancant par 7 ==> CP : 70550 DEPT : HAUTE-SAONE
Departement commancant par 7 ==> CP : 71270 DEPT : SAONE-ET-LOIRE
Departement commancant par 7 ==> CP : 72181 DEPT : SARTHE
Departement commancant par 7 ==> CP : 73065 DEPT : SAVOIE
Departement commancant par 7 ==> CP : 74010 DEPT : HAUTE-SAVOIE
Departement commancant par 7 ==> CP : 75056 DEPT : PARIS
Departement commancant par 7 ==> CP : 76540 DEPT : SEINE-MARITIME
Departement commancant par 7 ==> CP : 77288 DEPT : SEINE-ET-MARNE
Departement commancant par 7 ==> CP : 78646 DEPT : YVELINES
Departement commancant par 7 ==> CP : 79191 DEPT : DEUX-SEVRES
Departement commancant par 8 ==> CP : 80021 DEPT : SOMME
Departement commancant par 8 ==> CP : 81004 DEPT : TARN
Departement commancant par 8 ==> CP : 82121 DEPT : TARN-ET-GARONNE
Departement commancant par 8 ==> CP : 83137 DEPT : VAR
Departement commancant par 8 ==> CP : 84007 DEPT : VAUCLUSE
Departement commancant par 8 ==> CP : 85191 DEPT : VENDEE
Departement commancant par 8 ==> CP : 86194 DEPT : VIENNE
Departement commancant par 8 ==> CP : 87085 DEPT : HAUTE-VIENNE
Departement commancant par 8 ==> CP : 88160 DEPT : VOSGES
Departement commancant par 8 ==> CP : 89024 DEPT : YONNE
Departement commancant par 9 ==> CP : 90010 DEPT : TERRITOIRE
Departement commancant par 9 ==> CP : 91228 DEPT : ESSONNE
Departement commancant par 9 ==> CP : 92050 DEPT : HAUTS-DE-SEINE
Departement commancant par 9 ==> CP : 93008 DEPT : SEINE-SAINT-DENIS
Departement commancant par 9 ==> CP : 94028 DEPT : VAL-DE-MARNE
Departement commancant par 9 ==> CP : 95500 DEPT : VAL-D'OISE
Departement commancant par 9 ==> CP : 97105 DEPT : GUADELOUPE
Departement commancant par 9 ==> CP : 97209 DEPT : MARTINIQUE
Departement commancant par 9 ==> CP : 97302 DEPT : GUYANE
Departement commancant par 9 ==> CP : 97411 DEPT : LA
Departement commancant par 9 ==> CP : 97608 DEPT : MAYOTTE
Nombre total de lignes : 102
Nombre de departements commencant par 0 : 9
Nombre de departements commencant par 1 : 10
Nombre de departements commencant par 2 : 11
Nombre de departements commencant par 3 : 10
Nombre de departements commencant par 4 : 10
Nombre de departements commencant par 5 : 10
Nombre de departements commencant par 6 : 10
Nombre de departements commencant par 7 : 10
Nombre de departements commencant par 8 : 10
Nombre de departements commencant par 9 : 11
$
Awk propose des structures de controle que l'on retrouve dans la plupart des langages de programmation. La syntaxe est héritée du langage C.
La partie else est facultative.
Syntaxe
if (condition) {
instruction
...
}
else {
instruction
...
}
Première syntaxe
for (initialisation ; condition ; incrementation) {
instruction
...
}
Deuxième syntaxe
for (cle in tableau) {
print cle , tableau[cle]
}
Syntaxe
while (condition) {
instruction
...
}
Syntaxe
do {
instruction
...
} while (condition)
Le mot clé break permet d'interrompre une boucle.
Principe
while (1) {
if (condition) break ;
instruction ;
}
Le mot clé continue permet de remonter immédiatement à la condition, sans exécuter la suite de la boucle.
Principe
while (1) {
if (condition) continue ;
instruction ;
}
L'instruction exit permet de terminer un script à tout moment en retournant un statut au système.
Exemple
{
if ( NF < 3 ) exit 1 ;
print $1, $2, $3
}
END {
exit 0
}
Dans le langage awk, il existe 2 types de tableaux
L'indice de départ est au choix.
Exemple
Traitement du fichier /etc/passwd.
Ligne 2, initialisation de la variable FS.
Ligne 5, le contenu de la variable $1 correspondant au user est stocké dans le tableau user[] indicé à partir de 1.
Ligne 8 à 10, on parcourt le tableau et on affiche le contenu en formatant l'affichage avec printf.
$ nl script5.awk
1 BEGIN {
2 FS=":"
3 }
4 {
5 user[NR]=$1
6 }
7 END {
8 for (indice = 1 ; indice <= NR ; indice++ ) {
9 printf ("User num %2d : %-20s\n" , indice , user[indice]) ;
10 }
11 }
Exécution
$ awk -f script5.awk /etc/passwd
User num 1 : root
User num 2 : daemon
User num 3 : bin
User num 4 : sys
User num 5 : sync
User num 6 : games
User num 7 : man
User num 8 : lp
User num 9 : mail
User num 10 : news
User num 11 : uucp
User num 12 : proxy
User num 13 : www-data
User num 14 : backup
User num 15 : list
User num 16 : irc
User num 17 : gnats
User num 18 : nobody
User num 19 : libuuid
User num 20 : postfix
User num 21 : sshd
User num 22 : mysql
$
Les tableaux associatifs ont leurs éléments indicés par une chaine de caractères. Cet indice alphanumérique est considéré comme la clé et l'élément correspondant est nommé valeur.
Exemple
Le fichier depts2012.txt liste tous les départements par numéro de région.
$ cat depts2012.txt
REGION DEP CHEFLIEU TNCC NCC NCCENR
82 01 01053 5 AIN Ain
22 02 02408 5 AISNE Aisne
83 03 03190 5 ALLIER Allier
93 04 04070 4 ALPES-DE-HAUTE-PROVENCE Alpes-de-Haute-Provence
93 05 05061 4 HAUTES-ALPES Hautes-Alpes
93 06 06088 4 ALPES-MARITIMES Alpes-Maritimes
82 07 07186 5 ARDECHE Ardèche
21 08 08105 4 ARDENNES Ardennes
...
11 95 95500 2 VAL-D'OISE Val-d'Oise
01 971 97105 3 GUADELOUPE Guadeloupe
02 972 97209 3 MARTINIQUE Martinique
03 973 97302 3 GUYANE Guyane
04 974 97411 0 LA REUNION La Réunion
06 976 97608 0 MAYOTTE Mayotte
$
Le script suivant doit compter le nombre de départements qu'il y a par numéro de région.
La section BEGIN est vide car il n'y a pas besoin d'initialiser des variables.
Ligne 3, une condition est renseignée afin de ne pas traiter la première ligne du fichier qui correspond aux en-têtes.
Ligne 4, mise à jour du tableau nbdepts[] ayant comme clé la valeur du premier champ correspondant au numéro de la région et incrémenté de 1 à chaque fois que le champ 1 de la ligne traitée correspond à la clé.
Ligne 7 à 9, on parcourt le tableau et on affiche les résultats.
$ nl script6.awk
1 BEGIN {
2 }
3 NR != 1{
4 nbdepts[$1]+=1
5 }
6 END {
7 for ( region in nbdepts) {
8 printf("Region num : %02d ==> %3d departement(s)\n" , region , nbdepts[region])
9 }
10 }
$
Exécution
$ awk -f script6.awk depts2012.txt
Region num : 01 ==> 1 departement(s)
Region num : 02 ==> 1 departement(s)
Region num : 03 ==> 1 departement(s)
Region num : 04 ==> 1 departement(s)
Region num : 11 ==> 8 departement(s)
Region num : 06 ==> 1 departement(s)
Region num : 21 ==> 4 departement(s)
Region num : 22 ==> 3 departement(s)
Region num : 23 ==> 2 departement(s)
Region num : 31 ==> 2 departement(s)
Region num : 24 ==> 6 departement(s)
Region num : 25 ==> 3 departement(s)
Region num : 26 ==> 4 departement(s)
Region num : 41 ==> 4 departement(s)
Region num : 42 ==> 2 departement(s)
Region num : 43 ==> 4 departement(s)
Region num : 52 ==> 5 departement(s)
Region num : 53 ==> 4 departement(s)
Region num : 54 ==> 4 departement(s)
Region num : 72 ==> 5 departement(s)
Region num : 73 ==> 8 departement(s)
Region num : 74 ==> 3 departement(s)
Region num : 82 ==> 8 departement(s)
Region num : 83 ==> 4 departement(s)
Region num : 91 ==> 5 departement(s)
Region num : 93 ==> 6 departement(s)
Region num : 94 ==> 2 departement(s)
$
Le mot clé in permet de tester l'existence d'une clé dans un tableau associatif. Cette expression retourne vrai si la clé est présente, faux dans le cas contraire.
cle in tableau
Cette expression peut donc être utilisée comme condition d'une structure de contrôle.
if ( cle in tableau ) {
...
...
}
Il est possible de supprimer un élément d'un tableau associatif en utilisant la syntaxe suivante.
delete tableau[cle]
La paire clé-valeur est supprimée.
awk fourni un mécanisme qui permet de passer des arguments à un script au moment de son appel. Les variables ARGC et ARGV sont initialisées par awk et permettent de traiter les valeurs passées sur la ligne de commandes. La syntaxe doit être obligatroirement du genre var=value et placé avant le ou les fichiers à traiter.
Exemple
Avec le fichier depts2012.txt. Ecrire un script awk permettant de rechercher dans le fichier des enregistrements bien précis en lui passant comme argument un code région (champ 1), un code département (champ 2), un code postal (champ3) ou un département (champ5).
$ cat depts2012.txt
REGION DEP CHEFLIEU TNCC NCC NCCENR
82 01 01053 5 AIN Ain
22 02 02408 5 AISNE Aisne
83 03 03190 5 ALLIER Allier
93 04 04070 4 ALPES-DE-HAUTE-PROVENCE Alpes-de-Haute-Provence
93 05 05061 4 HAUTES-ALPES Hautes-Alpes
93 06 06088 4 ALPES-MARITIMES Alpes-Maritimes
82 07 07186 5 ARDECHE Ardèche
21 08 08105 4 ARDENNES Ardennes
...
11 92 92050 4 HAUTS-DE-SEINE Hauts-de-Seine
11 93 93008 3 SEINE-SAINT-DENIS Seine-Saint-Denis
11 94 94028 2 VAL-DE-MARNE Val-de-Marne
11 95 95500 2 VAL-D'OISE Val-d'Oise
01 971 97105 3 GUADELOUPE Guadeloupe
02 972 97209 3 MARTINIQUE Martinique
03 973 97302 3 GUYANE Guyane
04 974 97411 0 LA_REUNION La Réunion
06 976 97608 0 MAYOTTE Mayotte
$
Le script suivant traitera au maximum 4 arguments. La variable $1 devra être strictement égale à la valeur de l'argument coderegion, la variable $2 devra être strictement égale à la valeur de l'argument codedept, la variable $3 devra être strictement égale à la valeur de l'argument codepostal et enfin la variable $5 devra être strictement égale à la valeur de l'argument dept. Tous ces arguments sont bien sûr facultatifs. Les instructions next permettent de ne pas afficher plusieurs fois une même ligne correspondante à plusieurs sections intermédiaires.
$ nl script9.awk
1 BEGIN {
2 print "ARGC = " , ARGC
3 for (i=0 ; i<ARGC ; i++) {
4 printf ("ARGV[%d] = %s\n", i , ARGV[i])
5 }
6 }
7 $1 == coderegion {
8 print $0
9 next
10 }
11 $2 == codedept {
12 print $0
13 next
14 }
15 $3 == codepostal {
16 print $0
17 next
18 }
19 $5 == dept {
20 print $0
21 next
22 }
$
Exécution du script ayant comme argument de recherche coderegion=93
$ awk -f script9.awk coderegion=93 depts2012.txt
ARGC = 3
ARGV[0] = awk
ARGV[1] = coderegion=93
ARGV[2] = depts2012.txt
93 04 04070 4 ALPES-DE-HAUTE-PROVENCE Alpes-de-Haute-Provence
93 05 05061 4 HAUTES-ALPES Hautes-Alpes
93 06 06088 4 ALPES-MARITIMES Alpes-Maritimes
93 13 13055 4 BOUCHES-DU-RHONE Bouches-du-Rhône
93 83 83137 2 VAR Var
93 84 84007 0 VAUCLUSE Vaucluse
$
Exécution du script ayant comme argument de recherche codedept=44
$ awk -f script9.awk codedept=44 depts2012.txt
ARGC = 3
ARGV[0] = awk
ARGV[1] = codedept=44
ARGV[2] = depts2012.txt
52 44 44109 3 LOIRE-ATLANTIQUE Loire-Atlantique
$
Exécution du script ayant comme argument de recherche codepostal=85191
$ awk -f script9.awk codepostal=85191 depts2012.txt
ARGC = 3
ARGV[0] = awk
ARGV[1] = codepostal=85191
ARGV[2] = depts2012.txt
52 85 85191 3 VENDEE Vendée
$
Exécution du script ayant comme argument de recherche dept=VAR
$ awk -f script9.awk dept=VAR depts2012.txt
ARGC = 3
ARGV[0] = awk
ARGV[1] = dept=VAR
ARGV[2] = depts2012.txt
93 83 83137 2 VAR Var
$
Exécution du script avec tous les arguments renseignés
$ awk -f script9.awk coderegion=93 codedept=44 codepostal=75056 dept=HAUTE-SAVOIE depts2012.txt
ARGC = 6
ARGV[0] = awk
ARGV[1] = coderegion=93
ARGV[2] = codedept=44
ARGV[3] = codepostal=75056
ARGV[4] = dept=HAUTE-SAVOIE
ARGV[5] = depts2012.txt
93 04 04070 4 ALPES-DE-HAUTE-PROVENCE Alpes-de-Haute-Provence
93 05 05061 4 HAUTES-ALPES Hautes-Alpes
93 06 06088 4 ALPES-MARITIMES Alpes-Maritimes
93 13 13055 4 BOUCHES-DU-RHONE Bouches-du-Rhône
52 44 44109 3 LOIRE-ATLANTIQUE Loire-Atlantique
82 74 74010 3 HAUTE-SAVOIE Haute-Savoie
11 75 75056 0 PARIS Paris
93 83 83137 2 VAR Var
93 84 84007 0 VAUCLUSE Vaucluse
$
En plus de fonctions de base, awk dispose également de fonctions dédiées aux traitements des chaines de caractères, facilitant ce genre d'opérations. La liste de ces fonctions est la suivante :
Fonction de string | Description |
---|---|
gsub(exp,sub,str) | Substitue globalement par la chaine sub chaque expression régulière exp trouvée dans la chaine str et retourne le nombre de substitutions. Si str n'est pas indiquée, par défaut $0 est utilisé. |
index(str,st) |
Retourne la position du string st dans la chaine str, ou 0 si non trouvé. |
length(str) | Retourne la longueur de la chaine str. Si str n'est pas indiquée, par défaut $0 est utilisé. |
match(str,exp) | Retourne la position de l'expression régulière exp dans la chaine str, ou 0 si non trouvé. Affecte les valeurs aux variables RSTART et RLENGTH. |
split(str,tab,sep) | Sépare la chaine str en éléments dans un tableau tab et en utilisant le séparateur sep. Si sep n'est pas renseigné, FS est utilisé par défaut. |
sprintf("format",exp) | Retourne une chaine au lieu de l'affichage vers la sortie standard, contrairement à printf(). |
sub(exp,sub,str) | Comme gsub(), mais ne substitue par sub que la première expression exp trouvée dans str. |
substr(str,pos,long) | Retourne une partie du string str commançant à la position pos et de longueur long. Si long n'est pas indiqué, substr() utilise tout le reste de str. |
tolower(str) | Met en minuscules toute la chaine str et retourne la nouvelle chaine. |
toupper(str) | Met en majuscules toute la chaine str et retourne la nouvelle chaine. |
Exemple :
gsub : remplacer par un @ toutes les lettres a et A du fichier depts2012.txt
$ head depts2012.txt | awk '{gsub(/a|A/,"@") ; print}'
REGION DEP CHEFLIEU TNCC NCC NCCENR
82 01 01053 5 @IN @in
22 02 02408 5 @ISNE @isne
83 03 03190 5 @LLIER @llier
93 04 04070 4 @LPES-DE-H@UTE-PROVENCE @lpes-de-H@ute-Provence
93 05 05061 4 H@UTES-@LPES H@utes-@lpes
93 06 06088 4 @LPES-M@RITIMES @lpes-M@ritimes
82 07 07186 5 @RDECHE @rdèche
21 08 08105 4 @RDENNES @rdennes
73 09 09122 5 @RIEGE @riège
$
index : connaitre la position d'un caractère dans une chaine
$ head depts2012.txt | awk '{pos=index($5,"-") ; print "Position du tiret : " , pos , "\tdans la chaine : " , $5}'
Position du tiret : 0 dans la chaine : NCC
Position du tiret : 0 dans la chaine : AIN
Position du tiret : 0 dans la chaine : AISNE
Position du tiret : 0 dans la chaine : ALLIER
Position du tiret : 6 dans la chaine : ALPES-DE-HAUTE-PROVENCE
Position du tiret : 7 dans la chaine : HAUTES-ALPES
Position du tiret : 6 dans la chaine : ALPES-MARITIMES
Position du tiret : 0 dans la chaine : ARDECHE
Position du tiret : 0 dans la chaine : ARDENNES
Position du tiret : 0 dans la chaine : ARIEGE
$
length : connaitre le nombre de caractères dans une chaine
$ tail depts2012.txt | awk '{lg=length($5) ; printf ("Il y a %3d caracteres dans la chaine %30s\n" , lg , $5)}'
Il y a 7 caracteres dans la chaine ESSONNE
Il y a 14 caracteres dans la chaine HAUTS-DE-SEINE
Il y a 17 caracteres dans la chaine SEINE-SAINT-DENIS
Il y a 12 caracteres dans la chaine VAL-DE-MARNE
Il y a 10 caracteres dans la chaine VAL-D'OISE
Il y a 10 caracteres dans la chaine GUADELOUPE
Il y a 10 caracteres dans la chaine MARTINIQUE
Il y a 6 caracteres dans la chaine GUYANE
Il y a 10 caracteres dans la chaine LA_REUNION
Il y a 7 caracteres dans la chaine MAYOTTE
$
match : connaitre la position d'une expression dans une chaine
$ tail depts2012.txt | awk '{pos=match($5,/-DE-/) ; printf("Position de l expression recherchee \"-DE-\" : %2d dans la chaine %20s\tRSTART = %2d\tRLENGTH = %2d\n" , pos , $5 , RSTART , RLENGTH)}'
Position de l expression recherchee "-DE-" : 0 dans la chaine ESSONNE RSTART = 0 RLENGTH = -1
Position de l expression recherchee "-DE-" : 6 dans la chaine HAUTS-DE-SEINE RSTART = 6 RLENGTH = 4
Position de l expression recherchee "-DE-" : 0 dans la chaine SEINE-SAINT-DENIS RSTART = 0 RLENGTH = -1
Position de l expression recherchee "-DE-" : 4 dans la chaine VAL-DE-MARNE RSTART = 4 RLENGTH = 4
Position de l expression recherchee "-DE-" : 0 dans la chaine VAL-D'OISE RSTART = 0 RLENGTH = -1
Position de l expression recherchee "-DE-" : 0 dans la chaine GUADELOUPE RSTART = 0 RLENGTH = -1
Position de l expression recherchee "-DE-" : 0 dans la chaine MARTINIQUE RSTART = 0 RLENGTH = -1
Position de l expression recherchee "-DE-" : 0 dans la chaine GUYANE RSTART = 0 RLENGTH = -1
Position de l expression recherchee "-DE-" : 0 dans la chaine LA_REUNION RSTART = 0 RLENGTH = -1
Position de l expression recherchee "-DE-" : 0 dans la chaine MAYOTTE RSTART = 0 RLENGTH = -1
$
split : séparer une chaine en éléments dans un tableau
$ tail depts2012.txt | awk '/-/{split($5,tab,"-") ; printf("tab1 = %10s\ttab2 = %10s\ttab3 = %10s\n" , tab[1] , tab[2] , tab[3])}'
tab1 = HAUTS tab2 = DE tab3 = SEINE
tab1 = SEINE tab2 = SAINT tab3 = DENIS
tab1 = VAL tab2 = DE tab3 = MARNE
tab1 = VAL tab2 = D'OISE tab3 =
$
sprintf (contrairement à la commande printf, avec sprintf le retour chariot \n n'est pas obligatoire)
$ tail depts2012.txt | awk '/-/{split($5,tab,"-") ; chaine=sprintf("tab1 = %10s\ttab2 = %10s\ttab3 = %10s" , tab[1] , tab[2] , tab[3]) ; print chaine}'
tab1 = HAUTS tab2 = DE tab3 = SEINE
tab1 = SEINE tab2 = SAINT tab3 = DENIS
tab1 = VAL tab2 = DE tab3 = MARNE
tab1 = VAL tab2 = D'OISE tab3 =
$
sub : remplacer par un @ la première lettre a ou A de chaque ligne du fichier depts2012.txt
$ head depts2012.txt | awk '{sub(/a|A/,"@") ; print}'
REGION DEP CHEFLIEU TNCC NCC NCCENR
82 01 01053 5 @IN Ain
22 02 02408 5 @ISNE Aisne
83 03 03190 5 @LLIER Allier
93 04 04070 4 @LPES-DE-HAUTE-PROVENCE Alpes-de-Haute-Provence
93 05 05061 4 H@UTES-ALPES Hautes-Alpes
93 06 06088 4 @LPES-MARITIMES Alpes-Maritimes
82 07 07186 5 @RDECHE Ardèche
21 08 08105 4 @RDENNES Ardennes
73 09 09122 5 @RIEGE Ariège
$
substr : extraire une partie d'une chaine
$ tail depts2012.txt | awk '{chaine=substr($5,1,3) ; printf("Les 3 premieres lettres de %20s sont : %3s\n" , $5 , chaine)}'
Les 3 premieres lettres de ESSONNE sont : ESS
Les 3 premieres lettres de HAUTS-DE-SEINE sont : HAU
Les 3 premieres lettres de SEINE-SAINT-DENIS sont : SEI
Les 3 premieres lettres de VAL-DE-MARNE sont : VAL
Les 3 premieres lettres de VAL-D'OISE sont : VAL
Les 3 premieres lettres de GUADELOUPE sont : GUA
Les 3 premieres lettres de MARTINIQUE sont : MAR
Les 3 premieres lettres de GUYANE sont : GUY
Les 3 premieres lettres de LA_REUNION sont : LA_
Les 3 premieres lettres de MAYOTTE sont : MAY
$
tolower : convertir une chaine majuscule en minuscule
$ tail depts2012.txt | awk '{chaine=tolower($5) ; printf("%20s en minuscule : %20s\n" , $5 , chaine)}'
ESSONNE en minuscule : essonne
HAUTS-DE-SEINE en minuscule : hauts-de-seine
SEINE-SAINT-DENIS en minuscule : seine-saint-denis
VAL-DE-MARNE en minuscule : val-de-marne
VAL-D'OISE en minuscule : val-d'oise
GUADELOUPE en minuscule : guadeloupe
MARTINIQUE en minuscule : martinique
GUYANE en minuscule : guyane
LA_REUNION en minuscule : la_reunion
MAYOTTE en minuscule : mayotte
$
toupper : convertir une chaine minuscule en majuscule
$ tail depts2012.txt | awk '{chaine=toupper($6) ; printf("%20s en MAJUSCULE : %20s\n" , $6 , chaine)}'
Essonne en MAJUSCULE : ESSONNE
Hauts-de-Seine en MAJUSCULE : HAUTS-DE-SEINE
Seine-Saint-Denis en MAJUSCULE : SEINE-SAINT-DENIS
Val-de-Marne en MAJUSCULE : VAL-DE-MARNE
Val-d'Oise en MAJUSCULE : VAL-D'OISE
Guadeloupe en MAJUSCULE : GUADELOUPE
Martinique en MAJUSCULE : MARTINIQUE
Guyane en MAJUSCULE : GUYANE
Mayotte en MAJUSCULE : MAYOTTE
$
awk dispose également de fonctions dédiées aux traitements numériques. Celles-ci sont les suivantes :
Fonction mathématique | Description |
---|---|
cos(r) | Cosinus de l'angle r (r en radians) |
exp(x) | Exponentiel de x |
int(x) | Valeur entière de x |
log(x) | Logarithme de x |
sin(r) | Sinus de l'angle r (r en radians) |
sqrt(x) | Racine carrée de x |
atan2(y,x) | Arc tangente de y/x |
rand() | Nombre pseudo-aléatoire compris entre 0 et 1 |
srand(n) | Réinitialise la fonction rand() |
Exemple :
cos
$ echo 50 | awk '{print cos($1)}'
0.964966
$
exp
$ echo 5 | awk '{print exp($1)}'
148.413
$
int
$ echo 5.4 | awk '{print $1 , " ==> " , int($1)}'
5.4 ==> 5
$
log
$ echo 5 | awk '{print log($1)}'
1.60944
$
sin
$ echo 50 | awk '{print sin($1)}'
-0.262375
$
sqrt
$ echo 81 | awk '{print sqrt($1)}'
9
$
atan2
$ echo 50 25 | awk '{print atan2($1,$2)}'
1.10715
$
rand
$ echo | awk '{print rand()}'
0.795735
$ echo | awk '{print rand()}'
0.321886
$ echo | awk '{print int(rand()*1000)}'
792
$
La fonction getline permet de lire la ligne suivante du flux sans remonter au début du traitement (contrairement à next) et de lire une ligne à partir d'un fichier, de l'entrée standard ou d'un tube.
Valeur de retour :
- 1 en cas de succès
- 0 en fin de fichier
- -1 en cas d'erreur
Il ne faut pas mettre de parenthèse lors de l'appel de la fonction getline.
Syntaxe
getline [variable]
Lecture de la ligne suivante du flux.
getline [variable] < "fichier"
Lecture d'une ligne à partir d'un fichier
"commande" | getline [variable]
Lecture d'une ligne provenant du résultat d'une commande du système.
La ligne lue par getline est stockée dans la variable variable ou $0 si aucun nom de variable n'est spécifié. Le nom de fichier "-" représente l'entrée standard.
Premier exemple :
Reconstituer des phrases écrites sur plusieurs lignes et délimitées par un caractère spécifique.
Le fichier suivant contient des phrases scindées en plusieurs lignes. Le scindement est caractérisé par un anti-slash en fin de ligne.
$ cat text.txt
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. \
Maecenas porttitor congue massa. \
Fusce posuere, magna sed pulvinar ultricies,purus lectus malesuada libero, \
sit amet commodo magna eros quis urna.
Nunc viverra imperdiet enim. \
Fusce est. \
Vivamus a tellus.
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. \
Proin pharetra nonummy pede. Mauris et orci.
Aenean nec lorem. In porttitor. Donec laoreet nonummy augue.
Suspendisse dui purus, scelerisque at, vulputate vitae, pretium mattis, nunc. \
Mauris eget neque at sem venenatis eleifend. \
Ut nonummy.
$.
Le script suivant va analyser chaque ligne du fichier et reconstituer l'intégralité des phrases grâce à la fonction getline.
$ nl script10.awk
1 {
2 ligne=$0
3 # Tant que la ligne se termine par \
4 while(ligne ~ /\\$/){
5 # Suppression de \
6 sub(/\\$/,"",ligne)
7 # Lecture de la ligne suivante
8 getline nextline
9 # Concatenation de ligne et nextline
10 ligne=ligne nextline
11 }
12 # Affichage de la ligne globale
13 printf("------- Contenu de la phrase %d -------\n%s\n",++num,ligne)
14 }
$
Exécution du script
$ awk -f script10.awk text.txt
------- Contenu de la phrase 1 -------
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas porttitor congue massa. Fusce posuere, magna sed pulvinar ultricies,purus lectus malesuada libero, sit amet commodo magna eros quis urna.
------- Contenu de la phrase 2 -------
Nunc viverra imperdiet enim. Fusce est. Vivamus a tellus.
------- Contenu de la phrase 3 -------
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Proin pharetra nonummy pede. Mauris et orci.
------- Contenu de la phrase 4 -------
Aenean nec lorem. In porttitor. Donec laoreet nonummy augue.
------- Contenu de la phrase 5 -------
Suspendisse dui purus, scelerisque at, vulputate vitae, pretium mattis, nunc. Mauris eget neque at sem venenatis eleifend. Ut nonummy.
$
Deuxième exemple :
Lire une entrée clavier et le contenu d'un fichier extérieur au flux courant.
Rechercher le nom d'un département dans le fichier depts2012.txt en saisissant son nom au clavier.
$ cat depts2012.txt
REGION DEP CHEFLIEU TNCC NCC NCCENR
82 01 01053 5 AIN Ain
22 02 02408 5 AISNE Aisne
83 03 03190 5 ALLIER Allier
93 04 04070 4 ALPES-DE-HAUTE-PROVENCE Alpes-de-Haute-Provence
93 05 05061 4 HAUTES-ALPES Hautes-Alpes
...
01 971 97105 3 GUADELOUPE Guadeloupe
02 972 97209 3 MARTINIQUE Martinique
03 973 97302 3 GUYANE Guyane
04 974 97411 0 LA_REUNION La Réunion
06 976 97608 0 MAYOTTE Mayotte
$
Le script suivant demande une saisie au clavier et recherche dans le fichier précédent le nom saisi.
$ nl script11.awk
1 BEGIN{
2 # Boucle infinie
3 while(1){
4 printf("Rechercher le nom (ctrl+d pour quitter): ")
5 # Lecture clavier sur l'entree standard "-"
6 # Arret du programme si le code retour de getline est different de 1
7 if((getline nom < "-") != 1) break
8 # Si aucun nom saisi, on recommence
9 if(length(nom)==0) continue
10 trouve="false"
11 # Boucle de lecture du fichier depts2012.txt
12 # Tant que le code retour de getline est egal a 1
13 while((getline < "depts2012.txt")==1){
14 # Comparaison faite sans tenir compte de la casse
15 if(tolower($5)==tolower(nom)){
16 trouve="true"
17 # Affichage du resultat trouve
18 print $0
19 # On sort de la boucle while
20 break
21 }
22 }
23 # Fermeture du fichier
24 close("depts2012.txt")
25 # Affichage du message si le nom n'a pas ete trouve
26 if(trouve=="false") print nom , "n'est pas dans le fichier"
27 }
28 # Affichage du message avant l'arret du programme
29 print "\nA bientot"
30 }
$
Exécution du script
$ awk -f script11.awk
Rechercher le nom (ctrl+d pour quitter): ain
82 01 01053 5 AIN Ain
Rechercher le nom (ctrl+d pour quitter): somme
22 80 80021 3 SOMME Somme
Rechercher le nom (ctrl+d pour quitter):
Rechercher le nom (ctrl+d pour quitter): var
93 83 83137 2 VAR Var
Rechercher le nom (ctrl+d pour quitter):
A bientot
$
Troisième exemple :
Utiliser getline pour lire le résulat d'une commande système.
$ nl script12.awk
1 BEGIN{
2 "date" | getline
3 print "$0 = ",$0
4 for(i=1;i<=NF;i++){
5 printf("$%d = %s\n",i,$i)
6 }
7 }
$ awk -f script12.awk
$0 = Tue May 15 19:35:25 CEST 2012
$1 = Tue
$2 = May
$3 = 15
$4 = 19:35:25
$5 = CEST
$6 = 2012
$
La fonction close permet de fermer un fichier ou un tube de communication. Si l'appel à cette fonction est omis, les ressources sont libérées à la terminaison du script.
L'ordre de fermeture est intéressant dans les cas suivants :
- pouvoir se repositionner en début de fichier au sein du même processus (fermeture puis réouverture)
- fermer un tube de communication pour s'en servir à nouveau
- libérer les ressources au fur et à mesure des besoins (le système limite les processus, en ce qui concerne le nombre de fichiers/tubes ouverts simultanément).
Syntaxe
close("fichier")
close("commande")
Il est indispensable de fermer un fichier pour pouvoir le relire à partir du début.
Exemple :
$ nl script13.awk
1 BEGIN {
2 fichier = "/root/fichier1.txt"
3 i=1
4 while(i<=10){
5 print rand() > fichier
6 i++
7 }
8 # Fermeture du fichier
9 close(fichier)
10 while((getline<fichier)==1){
11 print $0
12 }
13 }
$ awk -f script13.awk
0.692303
0.532958
0.423364
0.484409
0.455168
0.0133607
0.554077
0.375875
0.325945
0.164046
$
La fonction system permet d'exécuter une commande du système.
Syntaxe
system("commande")
La fonction retourne le statut renvoyé par la commande.
Exemple :
$ awk 'BEGIN{system("uptime")}'
21:06:15 up 5 days, 2:22, 0 users, load average: 0.00, 0.00, 0.00
$
Idem mais en se servant d'une variable
$ awk 'BEGIN{fic="depts2012.txt";system("ls -l " fic)}'
-rw-r--r-- 1 root root 3504 May 10 14:05 depts2012.txt
$
Les fonctions personnelles peuvent être définies dans le script awk, en dehors des blocs d'instructions, ou dans un autre script qui sera également appelé par l'option -f <script>.
Une fonction se définit par le mot clé function suivi du nom de la fonction et de ses paramètres. Une fonction peut recevoir de 0 à n arguments et retourner une valeur explicite.
Syntaxe
function nom_fonction (param1, param2, ..., paramn) {
instructions
return valeur
}
Tous les paramètres de la fonction sont des variables locales. Toute autre variable définie dans la fonction est globale.
Appel d'une fonction
valeur=nom_fonction(val1, val2, ..., valn)
Il ne doit pas y avoir d'espace entre le nom de la fonction et la parenthèse ouvrante.
Exemple
$ nl script14.awk
1 function modulo(nb){
2 mod=nb%2
3 if(mod==0){
4 chaine=sprintf("%d est un nombre pair" , nb)
5 }
6 else{
7 chaine=sprintf("%d est un nombre impair" , nb)
8 }
9 return chaine
10 }
11 {
12 for(i=1;i<=NF;i++){
13 print modulo($i)
14 }
15 }
$ echo "20 21 23 56 43 2.4 rr" | awk -f script14.awk
20 est un nombre pair
21 est un nombre impair
23 est un nombre impair
56 est un nombre pair
43 est un nombre impair
2 est un nombre impair
0 est un nombre pair
$
Le script suivant analyse les logs postfix et retourne le nombre de messages par code erreur SMTP.
3 niveaux de visualisation sont proposés dont le jour et le mois en cours.
Pour fonctionner, le script à besoin d'un fichier additionnel répertoriant la liste des codes erreurs et leurs descriptions.
Téléchargement des fichiers :
Détail du fichier codeErrorSmtp :
$ cat codeErrorSmtp
X.1.0|Other address status
X.1.1|Bad destination mailbox address
X.1.2|Bad destination system address
X.1.3|Bad destination mailbox address syntax
X.1.4|Destination mailbox address ambiguous
X.1.5|Destination mailbox address valid
X.1.6|Mailbox has moved
X.1.7|Bad sender's mailbox address syntax
X.1.8|Bad sender's system address
X.2.0|Other or undefined mailbox status
X.2.1|Mailbox disabled, not accepting messages
X.2.2|Mailbox full
X.2.3|Message length exceeds administrative limit.
X.2.4|Mailing list expansion problem
X.3.0|Other or undefined mail system status
X.3.1|Mail system full
X.3.2|System not accepting network messages
X.3.3|System not capable of selected features
X.3.4|Message too big for system
X.4.0|Other or undefined network or routing status
X.4.1|No answer from host
X.4.2|Bad connection
X.4.3|Routing server failure
X.4.4|Unable to route
X.4.5|Network congestion
X.4.6|Routing loop detected
X.4.7|Delivery time expired
X.5.0|Other or undefined protocol status
X.5.1|Invalid command
X.5.2|Syntax error
X.5.3|Too many recipients
X.5.4|Invalid command arguments
X.5.5|Wrong protocol version
X.6.0|Other or undefined media error
X.6.1|Media not supported
X.6.2|Conversion required and prohibited
X.6.3|Conversion required but not supported
X.6.4|Conversion with loss performed
X.6.5|Conversion failed
X.7.0|Other or undefined security status
X.7.1|Delivery not authorized, message refused
X.7.2|Mailing list expansion prohibited
X.7.3|Security conversion required but not possible
X.7.4|Security features not supported
X.7.5|Cryptographic failure
X.7.6|Cryptographic algorithm not supported
X.7.7|Message integrity failure
$
Détail du script commenté :
$ nl mail.awk
1 BEGIN{
2 # Si le nombre d'arguments est egal a 1
3 # Arret du programme
4 # Il faut au moins 2 arguments (1 nom de fichier de log)
5 # Le script peut accepter plusieurs fichiers de log
6 if(ARGC==1){
7 print "Nombre d'arguments incorrect"
8 print "Syntaxe : awk -f mail.awk fichierLogMail1 [fichierLogMailn...]"
9 exit 1
10 }
11 # Initialisation de la variable contenant le nom du fichier
12 # des codes erreurs SMTP
13 errorSmtp="codeErrorSmtp"
14 # Execution d'une commande systeme pour tester si le fichier existe
15 # Arret du programme si le fichier n'existe pas
16 if((system("test -f " errorSmtp))==1){
17 print "Fichier codeErrorSmtp manquant"
18 exit 1
19 }
20 # Sauvegarde des donnees du fichier codeErrorSmtp
21 # dans un tableau associatif avec le code en cle
22 while((getline < errorSmtp) == 1){
23 ligne=$0
24 split(ligne,tab,"|")
25 tabErr[tab[1]]=tab[2]
26 }
27 # Fermeture du fichier codeErrorSmtp
28 close(errorSmtp)
29 # Affichage du menu
30 while(1){
31 # Si le choix est passe en argument
32 if(ARGV[1] ~ /^choix=/){
33 split(ARGV[1],tab,"=")
34 choix=tab[2]
35 if(choix>=1 && choix<=3) break
36 }
37 print "Choix date"
38 print " 1 - all"
39 print " 2 - day"
40 print " 3 - month"
41 printf("Choix : ")
42 # Lecture de l'entree clavier
43 # Si erreur, on quitte la boucle while
44 if((getline choix < "-")!=1) break
45 # Si aucune saisie, reaffichage du menu
46 if(length(choix)==0) continue
47 # Si le choix est compris entre 1 et 3 on quitte la boucle while
48 if(choix>=1 && choix<=3) break
49 }
50 deb=systime()
51 # Si le choix est egal a rien on quitte le programme
52 if(choix==""){
53 print "Bye"
54 exit 2
55 }
56 print "-------------------------------------------"
57 print "------- Analyse des fichiers de log -------"
58 print "-------------------------------------------"
59 }
60 # Lecture des fichiers de log
61 # Si la ligne courante contient l'expression recherchee
62 $0 ~ /[0-9][0-9][0-9] [0-9]\.[0-9]\.[0-9]/ && (choix==1 || (choix==2 && $1==getMonth() && $2==getDay()) || (choix==3 && $1==getMonth())) {
63 # Recherche de la position du premier caractere de l'expression xxx x.x.x
64 pos=match($0,/[0-9][0-9][0-9] [0-9]\.[0-9]\.[0-9]/)
65 # Extraction de l'expression xxx x.x.x
66 code=substr($0,pos,9)
67 # Sauvegarde de l'expression comme cle du tableau associatif
68 # et incrementation du compteur
69 codeSmtp[code]+=1
70 }
71 END{
72 # Parcourt du tableau associatif codeSmtp
73 totalMessages=0
74 for(i in codeSmtp){
75 # Affichage des lignes du tableau
76 # et de la description du code avec la fonction descCode
77 printf("Code %s (%-45s) ==> %5d message(s)\n",i,descCode(i),codeSmtp[i])
78 totalMessages+=codeSmtp[i]
79 }
80 # Fin du programme
81 fin=systime()
82 duree=fin-deb
83 printf("Total : %d messages\n%d lignes traitees en %d sec\n",totalMessages,NR,duree)
84 exit 0
85 }
86 # Fonction permettant la recherche de la description du code
87 function descCode(code){
88 # Extraction des 4 derniers caracteres du code à partir du 6eme caractere
89 codex=substr(code,6,4)
90 # Concatenation de la lettre "X" aux 4 derniers caracteres du code
91 codex="X" codex
92 # Extraction de la description en fonction du code
93 desc=tabErr[codex]
94 # Si le code erreur n'existe pas alors OK
95 desc=(desc != "" ? desc : "OK")
96 # Retour de la description au programme appelant
97 return desc
98 }
99 # Fonction permettant d'obtenir le numero du jour en cours
100 function getDay(){
101 day=int(strftime("%d"))
102 return day
103 }
104 # Fonction permettant d'obtenir le nom du mois en cours
105 function getMonth(){
106 month=strftime("%b")
107 return month
108 }
$
Exécution du script :
$ awk -f mail.awk /var/log/mail.log
Choix date
1 - all
2 - day
3 - month
Choix : 3
-------------------------------------------
------- Analyse des fichiers de log -------
-------------------------------------------
Code 554 5.7.1 (Delivery not authorized, message refused ) ==> 1992 message(s)
Code 550 5.1.1 (Bad destination mailbox address ) ==> 23 message(s)
Code 250 2.0.0 (OK ) ==> 1620 message(s)
Total : 3635 messages
42719 lignes traitees en 0 sec
$
En passant le choix de la date en argument :
$ awk -f mail.awk choix=3 /var/log/mail.log
-------------------------------------------
------- Analyse des fichiers de log -------
-------------------------------------------
Code 554 5.7.1 (Delivery not authorized, message refused ) ==> 1992 message(s)
Code 550 5.1.1 (Bad destination mailbox address ) ==> 23 message(s)
Code 250 2.0.0 (OK ) ==> 1620 message(s)
Total : 3635 messages
42719 lignes traitees en 0 sec
$
Exemple extrait du Linux/Magazine N° 131 d'octobre 2010 page 52.
Le script infoproc.awk utilise les fichiers virtuels /proc/cpuinfo et /proc/meminfo pour extraire les informations à afficher dans une page HTML infoproc.html. Les fichiers sont à placer en derniers paramètres et peuvent être traités différemment par les variables FILENAME et FNR. La sortie du script est redirigée vers le fichier infoproc.html.
L'en-tête et la fin de page HTML sont codés dans le bloc BEGIN et END.
Le fichier virtuel /proc/cpuinfo contient des enregistrements séparés par une ligne vide. Chaque champs des enregistrements est défini sur une ligne. Pour ce fichier, la variable de séparation d'enregistrement RS est donc égale à un saut de ligne "\n\n" et la variable de séparation des champs FS est égale à un retour-chariot "\n". Le fichier /proc/meminfo contient un seul enregistrement et les champs sont séparés par un retour-chariot, aussi les variables RS et FS n'ont pas à être modifiées entre ces fichiers.
Télécharger le script
Détail du script infoproc.awk
$ nl infoproc.awk
1 BEGIN{
2 RS="\n\n" # Separateur d'enregistrement
3 FS="\n" # Separateur de ligne
4 # En-tete et debut de page HTML
5 print "<html>"
6 print "<head>"
7 print "<title>Informations CPU et mémoire</title>"
8 print "<style type=\"text/css\">"
9 print "table {border: solid thin; padding 10px; margin 5px}"
10 print "table.proc {color: DarkSlateBlue; border-color: DarkSlateBlue}"
11 print "table.proc caption {color: white; background: DarkSlateBlue; text-align: center}"
12 print "table.mem {color: DarkGreen; border-color: DarkGreen}"
13 print "table.mem caption {color: white; background: DarkGreen; text-align: center}"
14 print "</style>"
15 print "</head>"
16 print "<body>"
17 print "<table><tr>"
18 }
19 FILENAME ~ /cpuinfo$/ { print "<td valign=\"top\"><table class=\"proc\">"}
20 FILENAME ~ /meminfo$/ { print "<td valign=\"top\"><table class=\"mem\">"}
21 {
22 for(i=1; i<=NF; i++){
23 split($i, cpu, ":")
24 if(i==1) print "<caption>", cpu[1], cpu[2], "</caption>"
25 else print "<tr><td>", cpu[1], "</td><td>", cpu[2], "</td></tr>"
26 }
27 print "</table></td>"
28 }
29 END{
30 # Fin de page HTML
31 print "</tr></table>"
32 print "</body>"
33 print "</html>"
34 }
$
Exécution du script
$ awk -f /root/infoproc.awk /proc/cpuinfo /proc/meminfo > /var/www/infoproc.html
Résultat obtenu
Fichier attaché | Taille |
---|---|
infoproc.html | 5.96 Ko |
Les commandes filtres traitent un flux de données issues de l'entrée standard ou contenues dans un fichier. Elles peuvent être utilisées de manière autonome ou placées derrière un tube de communication. Les filtres s'utilisent pour la plupart de la même manière.
Syntaxe
commande_filtre -options fic1 fic2 ... ficn
commande_filtre -options -
commande_filtre -options < fichier
commande | commande_filtre -options
Outre la consultation de données, voici quelques exemples d'utilisation de la commande cat.
Syntaxe
cat [options] [fichiers]
Principales options
-e Affiche le symbole "$" à la fin de chaque ligne
-t Affiche le symbole "^I" (i majuscule) à chaque tabulation
-v Matérialise les caractères non affichables
Exemples
Quand la commande cat ne reçoit pas de fichier en argument, elle affiche sur la sortie standard les données saisies sur l'entrée standard.
$ cat
ceci est un test # Texte saisi au clavier sur l'entrée standard
ceci est un test # Texte afficher automatiquement sur la sortie standard
^d
$
Ce qui est saisi sur l'entrée standard peut être enregistré dans un fichier
$ cat > fic1
ceci est un test
^d
$ cat fic1
ceci est un test
$
cat peut également concaténer des fichiers
$ cat fic1
ceci est un test
$ cat fic2
ceci est un autre test
$ cat fic1 fic2 > fic3
$ cat fic3
ceci est un test
ceci est un autre test
$
L'option -t permet de visualiser les tabulations. Celles-ci sont matérialisées par les caractères "^I" (i majuscule)
$ cat fic4
ceci est un test
$ cat -t fic4
ceci^Iest^Iun^Itest
$
L'option -e permet de visualiser les fins de ligne. Celles-ci sont matérialisées par le symbole "$"
$ cat -e fic4
ceci est un test$
$
L'option -A permet de visualiser tous les caractères non affichables
$ cat -A fic4
ceci^Iest^Iun^Itest$
$
La commande od permet de visualiser la valeur de chaque octet d'un fichier texte ou binaire. L'option -c permet une interprétation octet par octet. Il est ainsi possible de voir de manière exacte le contenu du fichier, de détecter l'emplacement des espaces, tabulations et caractères de sauts de ligne (CR, LF ou CR LF).
Avec od, les tabulations sont représentées par \t, les espaces par un espace, le caractère LF par \n
Exemple
$ cat fic5
ceci est un test
et un autre test
$ od -c fic5
0000000 c e c i e s t u n \t t e s t
0000020 \n e t u n \t a u t r e t e
0000040 s t \t \n
0000044
$
La colonne de gauche représente la position du premier caractère de la ligne dans le fichier, exprimée en octal.
La commande grep recherche une chaine de caractères dans un ou plusieurs fichiers textes et affiche à l'écran les lignes contenant cette chaine. La chaine recherchée est matérialisée par une expression régulière basique ERb (défaut) ou étendue ERe grâce à l'option -E.
Syntaxe
grep [options] expreg [fichiers...]
grep [options] -e expreg1 -e expreg2 [fichiers...]
grep [options] -f fichier_expreg [fichiers...]
Principales options :
-c affiche le nombre de lignes trouvées
-e permet de spécifier plusieurs expressions régulières
-E permet d'utiliser les ERe
-f permet de lire les expressions régulières à partir d'un fichier
-F permet de ne pas interpréter le motif de recherche comme une expression régulière
-i permet une recherche insensible à la casse
-l permet de seulement afficher les noms des fichiers contenant l'expression régulière recherchée
-n permet de numéroter les lignes trouvées
-q permet d'effectuer une recherche sans afficher le résultat à l'écran
-v permet une recherche ne contenant pas l'expression régulière
-w l'expression recherchée doit correspondre à un mot entier
-x l'expression recherchée doit correspondre à une ligne entière
-B n Affiche n lignes avant l'expression recherchée (-B pour Before)
-A n Affiche n lignes après l'expression recherchée (-A pour After)
-C n Affiche n lignes avant et après l'expression recherchée
-P permet d'utiliser des regex compatible PERL
Exemple
Utilisation du fichier depts2012.txt pour les exemples
$ cat depts2012.txt
REGION DEP CHEFLIEU TNCC NCC NCCENR
82 01 01053 5 AIN Ain
22 02 02408 5 AISNE Aisne
83 03 03190 5 ALLIER Allier
93 04 04070 4 ALPES-DE-HAUTE-PROVENCE Alpes-de-Haute-Provence
93 05 05061 4 HAUTES-ALPES Hautes-Alpes
93 06 06088 4 ALPES-MARITIMES Alpes-Maritimes
82 07 07186 5 ARDECHE Ardèche
21 08 08105 4 ARDENNES Ardennes
73 09 09122 5 ARIEGE Ariège
21 10 10387 5 AUBE Aube
91 11 11069 5 AUDE Aude
73 12 12202 5 AVEYRON Aveyron
93 13 13055 4 BOUCHES-DU-RHONE Bouches-du-Rhône
25 14 14118 2 CALVADOS Calvados
83 15 15014 2 CANTAL Cantal
54 16 16015 3 CHARENTE Charente
54 17 17300 3 CHARENTE-MARITIME Charente-Maritime
24 18 18033 2 CHER Cher
74 19 19272 3 CORREZE Corrèze
94 2A 2A004 3 CORSE-DU-SUD Corse-du-Sud
94 2B 2B033 3 HAUTE-CORSE Haute-Corse
26 21 21231 3 COTE-D'OR Côte-d'Or
53 22 22278 4 COTES-D'ARMOR Côtes-d'Armor
74 23 23096 3 CREUSE Creuse
72 24 24322 3 DORDOGNE Dordogne
43 25 25056 2 DOUBS Doubs
82 26 26362 3 DROME Drôme
23 27 27229 5 EURE Eure
24 28 28085 1 EURE-ET-LOIR Eure-et-Loir
53 29 29232 2 FINISTERE Finistère
91 30 30189 2 GARD Gard
73 31 31555 3 HAUTE-GARONNE Haute-Garonne
73 32 32013 2 GERS Gers
72 33 33063 3 GIRONDE Gironde
91 34 34172 5 HERAULT Hérault
53 35 35238 1 ILLE-ET-VILAINE Ille-et-Vilaine
24 36 36044 5 INDRE Indre
24 37 37261 1 INDRE-ET-LOIRE Indre-et-Loire
82 38 38185 5 ISERE Isère
43 39 39300 2 JURA Jura
72 40 40192 4 LANDES Landes
24 41 41018 0 LOIR-ET-CHER Loir-et-Cher
82 42 42218 3 LOIRE Loire
83 43 43157 3 HAUTE-LOIRE Haute-Loire
52 44 44109 3 LOIRE-ATLANTIQUE Loire-Atlantique
24 45 45234 2 LOIRET Loiret
73 46 46042 2 LOT Lot
72 47 47001 0 LOT-ET-GARONNE Lot-et-Garonne
91 48 48095 3 LOZERE Lozère
52 49 49007 0 MAINE-ET-LOIRE Maine-et-Loire
25 50 50502 3 MANCHE Manche
21 51 51108 3 MARNE Marne
21 52 52121 3 HAUTE-MARNE Haute-Marne
52 53 53130 3 MAYENNE Mayenne
41 54 54395 0 MEURTHE-ET-MOSELLE Meurthe-et-Moselle
41 55 55029 3 MEUSE Meuse
53 56 56260 2 MORBIHAN Morbihan
41 57 57463 3 MOSELLE Moselle
26 58 58194 3 NIEVRE Nièvre
31 59 59350 2 NORD Nord
22 60 60057 5 OISE Oise
25 61 61001 5 ORNE Orne
31 62 62041 2 PAS-DE-CALAIS Pas-de-Calais
83 63 63113 2 PUY-DE-DOME Puy-de-Dôme
72 64 64445 4 PYRENEES-ATLANTIQUES Pyrénées-Atlantiques
73 65 65440 4 HAUTES-PYRENEES Hautes-Pyrénées
91 66 66136 4 PYRENEES-ORIENTALES Pyrénées-Orientales
42 67 67482 2 BAS-RHIN Bas-Rhin
42 68 68066 2 HAUT-RHIN Haut-Rhin
82 69 69123 2 RHONE Rhône
43 70 70550 3 HAUTE-SAONE Haute-Saône
26 71 71270 0 SAONE-ET-LOIRE Saône-et-Loire
52 72 72181 3 SARTHE Sarthe
82 73 73065 3 SAVOIE Savoie
82 74 74010 3 HAUTE-SAVOIE Haute-Savoie
11 75 75056 0 PARIS Paris
23 76 76540 3 SEINE-MARITIME Seine-Maritime
11 77 77288 0 SEINE-ET-MARNE Seine-et-Marne
11 78 78646 4 YVELINES Yvelines
54 79 79191 4 DEUX-SEVRES Deux-Sèvres
22 80 80021 3 SOMME Somme
73 81 81004 2 TARN Tarn
73 82 82121 0 TARN-ET-GARONNE Tarn-et-Garonne
93 83 83137 2 VAR Var
93 84 84007 0 VAUCLUSE Vaucluse
52 85 85191 3 VENDEE Vendée
54 86 86194 3 VIENNE Vienne
74 87 87085 3 HAUTE-VIENNE Haute-Vienne
41 88 88160 4 VOSGES Vosges
26 89 89024 5 YONNE Yonne
43 90 90010 0 TERRITOIRE_DE_BELFORT Territoire de Belfort
11 91 91228 5 ESSONNE Essonne
11 92 92050 4 HAUTS-DE-SEINE Hauts-de-Seine
11 93 93008 3 SEINE-SAINT-DENIS Seine-Saint-Denis
11 94 94028 2 VAL-DE-MARNE Val-de-Marne
11 95 95500 2 VAL-D'OISE Val-d'Oise
01 971 97105 3 GUADELOUPE Guadeloupe
02 972 97209 3 MARTINIQUE Martinique
03 973 97302 3 GUYANE Guyane
04 974 97411 0 LA_REUNION La Réunion
06 976 97608 0 MAYOTTE Mayotte
$
$ grep 85191 depts2012.txt
52 85 85191 3 VENDEE Vendée
$
$ grep -E -i '(paris|vosges)' depts2012.txt
11 75 75056 0 PARIS Paris
41 88 88160 4 VOSGES Vosges
$
$ grep -v '^9' depts2012.txt
REGION DEP CHEFLIEU TNCC NCC NCCENR
82 01 01053 5 AIN Ain
22 02 02408 5 AISNE Aisne
83 03 03190 5 ALLIER Allier
82 07 07186 5 ARDECHE Ardèche
21 08 08105 4 ARDENNES Ardennes
73 09 09122 5 ARIEGE Ariège
21 10 10387 5 AUBE Aube
73 12 12202 5 AVEYRON Aveyron
25 14 14118 2 CALVADOS Calvados
83 15 15014 2 CANTAL Cantal
54 16 16015 3 CHARENTE Charente
54 17 17300 3 CHARENTE-MARITIME Charente-Maritime
24 18 18033 2 CHER Cher
74 19 19272 3 CORREZE Corrèze
26 21 21231 3 COTE-D'OR Côte-d'Or
53 22 22278 4 COTES-D'ARMOR Côtes-d'Armor
74 23 23096 3 CREUSE Creuse
72 24 24322 3 DORDOGNE Dordogne
43 25 25056 2 DOUBS Doubs
82 26 26362 3 DROME Drôme
23 27 27229 5 EURE Eure
24 28 28085 1 EURE-ET-LOIR Eure-et-Loir
53 29 29232 2 FINISTERE Finistère
73 31 31555 3 HAUTE-GARONNE Haute-Garonne
73 32 32013 2 GERS Gers
72 33 33063 3 GIRONDE Gironde
53 35 35238 1 ILLE-ET-VILAINE Ille-et-Vilaine
24 36 36044 5 INDRE Indre
24 37 37261 1 INDRE-ET-LOIRE Indre-et-Loire
82 38 38185 5 ISERE Isère
43 39 39300 2 JURA Jura
72 40 40192 4 LANDES Landes
24 41 41018 0 LOIR-ET-CHER Loir-et-Cher
82 42 42218 3 LOIRE Loire
83 43 43157 3 HAUTE-LOIRE Haute-Loire
52 44 44109 3 LOIRE-ATLANTIQUE Loire-Atlantique
24 45 45234 2 LOIRET Loiret
73 46 46042 2 LOT Lot
72 47 47001 0 LOT-ET-GARONNE Lot-et-Garonne
52 49 49007 0 MAINE-ET-LOIRE Maine-et-Loire
25 50 50502 3 MANCHE Manche
21 51 51108 3 MARNE Marne
21 52 52121 3 HAUTE-MARNE Haute-Marne
52 53 53130 3 MAYENNE Mayenne
41 54 54395 0 MEURTHE-ET-MOSELLE Meurthe-et-Moselle
41 55 55029 3 MEUSE Meuse
53 56 56260 2 MORBIHAN Morbihan
41 57 57463 3 MOSELLE Moselle
26 58 58194 3 NIEVRE Nièvre
31 59 59350 2 NORD Nord
22 60 60057 5 OISE Oise
25 61 61001 5 ORNE Orne
31 62 62041 2 PAS-DE-CALAIS Pas-de-Calais
83 63 63113 2 PUY-DE-DOME Puy-de-Dôme
72 64 64445 4 PYRENEES-ATLANTIQUES Pyrénées-Atlantiques
73 65 65440 4 HAUTES-PYRENEES Hautes-Pyrénées
42 67 67482 2 BAS-RHIN Bas-Rhin
42 68 68066 2 HAUT-RHIN Haut-Rhin
82 69 69123 2 RHONE Rhône
43 70 70550 3 HAUTE-SAONE Haute-Saône
26 71 71270 0 SAONE-ET-LOIRE Saône-et-Loire
52 72 72181 3 SARTHE Sarthe
82 73 73065 3 SAVOIE Savoie
82 74 74010 3 HAUTE-SAVOIE Haute-Savoie
11 75 75056 0 PARIS Paris
23 76 76540 3 SEINE-MARITIME Seine-Maritime
11 77 77288 0 SEINE-ET-MARNE Seine-et-Marne
11 78 78646 4 YVELINES Yvelines
54 79 79191 4 DEUX-SEVRES Deux-Sèvres
22 80 80021 3 SOMME Somme
73 81 81004 2 TARN Tarn
73 82 82121 0 TARN-ET-GARONNE Tarn-et-Garonne
52 85 85191 3 VENDEE Vendée
54 86 86194 3 VIENNE Vienne
74 87 87085 3 HAUTE-VIENNE Haute-Vienne
41 88 88160 4 VOSGES Vosges
26 89 89024 5 YONNE Yonne
43 90 90010 0 TERRITOIRE_DE_BELFORT Territoire de Belfort
11 91 91228 5 ESSONNE Essonne
11 92 92050 4 HAUTS-DE-SEINE Hauts-de-Seine
11 93 93008 3 SEINE-SAINT-DENIS Seine-Saint-Denis
11 94 94028 2 VAL-DE-MARNE Val-de-Marne
11 95 95500 2 VAL-D'OISE Val-d'Oise
01 971 97105 3 GUADELOUPE Guadeloupe
02 972 97209 3 MARTINIQUE Martinique
03 973 97302 3 GUYANE Guyane
04 974 97411 0 LA_REUNION La Réunion
06 976 97608 0 MAYOTTE Mayotte
$
$ grep -e '^0' -e 's$' depts2012.txt
93 05 05061 4 HAUTES-ALPES Hautes-Alpes
93 06 06088 4 ALPES-MARITIMES Alpes-Maritimes
21 08 08105 4 ARDENNES Ardennes
25 14 14118 2 CALVADOS Calvados
43 25 25056 2 DOUBS Doubs
73 32 32013 2 GERS Gers
72 40 40192 4 LANDES Landes
31 62 62041 2 PAS-DE-CALAIS Pas-de-Calais
72 64 64445 4 PYRENEES-ATLANTIQUES Pyrénées-Atlantiques
73 65 65440 4 HAUTES-PYRENEES Hautes-Pyrénées
91 66 66136 4 PYRENEES-ORIENTALES Pyrénées-Orientales
11 75 75056 0 PARIS Paris
11 78 78646 4 YVELINES Yvelines
54 79 79191 4 DEUX-SEVRES Deux-Sèvres
41 88 88160 4 VOSGES Vosges
11 93 93008 3 SEINE-SAINT-DENIS Seine-Saint-Denis
01 971 97105 3 GUADELOUPE Guadeloupe
02 972 97209 3 MARTINIQUE Martinique
03 973 97302 3 GUYANE Guyane
04 974 97411 0 LA_REUNION La Réunion
06 976 97608 0 MAYOTTE Mayotte
$
$ grep -n '^11' depts2012.txt
77:11 75 75056 0 PARIS Paris
79:11 77 77288 0 SEINE-ET-MARNE Seine-et-Marne
80:11 78 78646 4 YVELINES Yvelines
93:11 91 91228 5 ESSONNE Essonne
94:11 92 92050 4 HAUTS-DE-SEINE Hauts-de-Seine
95:11 93 93008 3 SEINE-SAINT-DENIS Seine-Saint-Denis
96:11 94 94028 2 VAL-DE-MARNE Val-de-Marne
97:11 95 95500 2 VAL-D'OISE Val-d'Oise
$
$ grep -q '^11' depts2012.txt
$ echo $?
0
$
$ grep -c -e '^0' -e 's$' depts2012.txt
21
$
$ grep COTE depts2012.txt # Sans l'option -w 2 lignes sont affichées
26 21 21231 3 COTE-D'OR Côte-d'Or
53 22 22278 4 COTES-D'ARMOR Côtes-d'Armor
$ grep -w COTE depts2012.txt # Avec l'option -w seule la ligne contenant le mot COTE s'affiche
26 21 21231 3 COTE-D'OR Côte-d'Or
$
$ cat fic7
erytert
e
er
..
uhy
2
e_
34
546
$ grep '..' fic7
erytert
er
..
uhy
e_
34
546
$
$ grep -F '..' fic7
..
$
$ grep -E '^[0-9]+$' << EOF # Sans l'option -x
5
455788
456 657588
elrerioyuerioy
sdgjhg4547457
56456456dgldkgdlfg
EOF
5
455788
$ grep -x -E '[0-9]+' << EOF # Avec l'option -x
5
455788
456 657588
elrerioyuerioy
sdgjhg4547457
56456456dgldkgdlfg
EOF
5
455788
$ cat rech.er
# Rechercher les lignes se terminant par la lettre t
t$
# Rechercher les lignes contenant uniquement des chiffres
^[0-9]+$
$ grep -E -f rech.er fic7
erytert
2
34
546
$
$ ps -ef | grep apache2
root 302 1 0 06:18 ? 00:00:00 /usr/sbin/apache2 -k start
www-data 351 302 0 06:18 ? 00:00:00 /usr/sbin/apache2 -k start
www-data 352 302 0 06:18 ? 00:00:00 /usr/sbin/apache2 -k start
root 3783 3105 0 14:10 pts/0 00:00:00 grep --color=always apache2
$
Dans ce cas, la commande grep apparait également. L'utilisation de 2 tubes est donc nécessaire.
$ ps -ef | grep apache2 | grep -v grep # On demande à grep de ne pas afficher "grep"
root 302 1 0 06:18 ? 00:00:00 /usr/sbin/apache2 -k start
www-data 351 302 0 06:18 ? 00:00:00 /usr/sbin/apache2 -k start
www-data 352 302 0 06:18 ? 00:00:00 /usr/sbin/apache2 -k start
$
$ grep -B 3 rose << EOF
Pont entier étroit composer détacher politique terrain.
Angoisse soulever aventure nécessaire sans installer plante.
Plante protéger prochain sentir paysage.
Pierre fort façon loin relation.
Saint accent hasard franchir.
Inutile rose nombre nécessaire président en robe.
Entre mener semaine déposer atteindre professeur rentrer.
Terrible choisir loi subir oser.
Sonner expliquer conduire soldat.
Étendue profond table beau chose.
EOF
Plante protéger prochain sentir paysage.
Pierre fort façon loin relation.
Saint accent hasard franchir.
Inutile rose nombre nécessaire président en robe.
$
$ grep -A 3 rose << EOF
Pont entier étroit composer détacher politique terrain.
Angoisse soulever aventure nécessaire sans installer plante.
Plante protéger prochain sentir paysage.
Pierre fort façon loin relation.
Saint accent hasard franchir.
Inutile rose nombre nécessaire président en robe.
Entre mener semaine déposer atteindre professeur rentrer.
Terrible choisir loi subir oser.
Sonner expliquer conduire soldat.
Étendue profond table beau chose.
EOF
Inutile rose nombre nécessaire président en robe.
Entre mener semaine déposer atteindre professeur rentrer.
Terrible choisir loi subir oser.
Sonner expliquer conduire soldat.
$
$ grep -C 1 rose << EOF
Pont entier étroit composer détacher politique terrain.
Angoisse soulever aventure nécessaire sans installer plante.
Plante protéger prochain sentir paysage.
Pierre fort façon loin relation.
Saint accent hasard franchir.
Inutile rose nombre nécessaire président en robe.
Entre mener semaine déposer atteindre professeur rentrer.
Terrible choisir loi subir oser.
Sonner expliquer conduire soldat.
Étendue profond table beau chose.
EOF
Saint accent hasard franchir.
Inutile rose nombre nécessaire président en robe.
Entre mener semaine déposer atteindre professeur rentrer.
$
Dans le texte suivant, le mot "nécessaire" existe 2 fois
$ grep nécessaire << EOF
Pont entier étroit composer détacher politique terrain.
Angoisse soulever aventure nécessaire sans installer plante.
Plante protéger prochain sentir paysage.
Pierre fort façon loin relation.
Saint accent hasard franchir.
Inutile rose nombre nécessaire président en robe.
Entre mener semaine déposer atteindre professeur rentrer.
Terrible choisir loi subir oser.
Sonner expliquer conduire soldat.
Étendue profond table beau chose.
EOF
Angoisse soulever aventure nécessaire sans installer plante.
Inutile rose nombre nécessaire président en robe.
$ grep -P '(?<=nombre) nécessaire' << EOF
Pont entier étroit composer détacher politique terrain.
Angoisse soulever aventure nécessaire sans installer plante.
Plante protéger prochain sentir paysage.
Pierre fort façon loin relation.
Saint accent hasard franchir.
Inutile rose nombre nécessaire président en robe.
Entre mener semaine déposer atteindre professeur rentrer.
Terrible choisir loi subir oser.
Sonner expliquer conduire soldat.
Étendue profond table beau chose.
EOF
Inutile rose nombre nécessaire président en robe.
$ grep -P 'nécessaire (?=sans)' << EOF
Pont entier étroit composer détacher politique terrain.
Angoisse soulever aventure nécessaire sans installer plante.
Plante protéger prochain sentir paysage.
Pierre fort façon loin relation.
Saint accent hasard franchir.
Inutile rose nombre nécessaire président en robe.
Entre mener semaine déposer atteindre professeur rentrer.
Terrible choisir loi subir oser.
Sonner expliquer conduire soldat.
Étendue profond table beau chose.
EOF
Angoisse soulever aventure nécessaire sans installer plante.
$ grep -P 'nécessaire (?!sans)' << EOF
Pont entier étroit composer détacher politique terrain.
Angoisse soulever aventure nécessaire sans installer plante.
Plante protéger prochain sentir paysage.
Pierre fort façon loin relation.
Saint accent hasard franchir.
Inutile rose nombre nécessaire président en robe.
Entre mener semaine déposer atteindre professeur rentrer.
Terrible choisir loi subir oser.
Sonner expliquer conduire soldat.
Étendue profond table beau chose.
EOF
Inutile rose nombre nécessaire président en robe.
$ grep -P '(?<!nombre) nécessaire' << EOF
Pont entier étroit composer détacher politique terrain.
Angoisse soulever aventure nécessaire sans installer plante.
Plante protéger prochain sentir paysage.
Pierre fort façon loin relation.
Saint accent hasard franchir.
Inutile rose nombre nécessaire président en robe.
Entre mener semaine déposer atteindre professeur rentrer.
Terrible choisir loi subir oser.
Sonner expliquer conduire soldat.
Étendue profond table beau chose.
EOF
Angoisse soulever aventure nécessaire sans installer plante.
La commande tail permet d'afficher, par défaut, les 10 dernières lignes d'un flux de données. Cette commande est souvent utilisée pour afficher les dernières lignes d'un fichier de log.
Syntaxe
tail [options] [fichiers ...]
Principales fonctions :
-f Affiche en temps réel les ajouts en fin de fichier
-n Affiche les n dernières lignes indiquées
-n +x Affiche à partir de la ligne x jusqu'à la fin du fichier
Exemples
Afficher les 5 dernières lignes du fichier /var/log/messages
$ tail -n 5 /var/log/messages # Utilisation de -n 5
May 18 14:09:12 rsyslogd: [origin software="rsyslogd" swVersion="4.6.4" x-pid="287" x-info="http://www.rsyslog.com"] (re)start
May 18 15:26:36 kernel: imklog 4.6.4, log source = /proc/kmsg started.
May 18 15:26:36 rsyslogd: [origin software="rsyslogd" swVersion="4.6.4" x-pid="285" x-info="http://www.rsyslog.com"] (re)start
May 19 06:18:39 kernel: imklog 4.6.4, log source = /proc/kmsg started.
May 19 06:18:39 rsyslogd: [origin software="rsyslogd" swVersion="4.6.4" x-pid="285" x-info="http://www.rsyslog.com"] (re)start
$ tail -5 /var/log/messages # Identique mais en indiquant seulement -5
May 18 14:09:12 rsyslogd: [origin software="rsyslogd" swVersion="4.6.4" x-pid="287" x-info="http://www.rsyslog.com"] (re)start
May 18 15:26:36 kernel: imklog 4.6.4, log source = /proc/kmsg started.
May 18 15:26:36 rsyslogd: [origin software="rsyslogd" swVersion="4.6.4" x-pid="285" x-info="http://www.rsyslog.com"] (re)start
May 19 06:18:39 kernel: imklog 4.6.4, log source = /proc/kmsg started.
May 19 06:18:39 rsyslogd: [origin software="rsyslogd" swVersion="4.6.4" x-pid="285" x-info="http://www.rsyslog.com"] (re)start
$
Afficher à partir de la ligne 9
$ tail -n +9 /var/log/messages
May 18 12:21:34 kernel: Kernel logging (proc) stopped.
May 18 12:21:34 rsyslogd: [origin software="rsyslogd" swVersion="4.6.4" x-pid="288" x-info="http://www.rsyslog.com"] exiting on signal 15.
May 18 14:09:12 kernel: imklog 4.6.4, log source = /proc/kmsg started.
May 18 14:09:12 rsyslogd: [origin software="rsyslogd" swVersion="4.6.4" x-pid="287" x-info="http://www.rsyslog.com"] (re)start
May 18 15:26:36 kernel: imklog 4.6.4, log source = /proc/kmsg started.
May 18 15:26:36 rsyslogd: [origin software="rsyslogd" swVersion="4.6.4" x-pid="285" x-info="http://www.rsyslog.com"] (re)start
May 19 06:18:39 kernel: imklog 4.6.4, log source = /proc/kmsg started.
May 19 06:18:39 rsyslogd: [origin software="rsyslogd" swVersion="4.6.4" x-pid="285" x-info="http://www.rsyslog.com"] (re)start
$
Afficher les dernières lignes d'un fichier en temps réel
$ tail -f /var/log/messages
May 18 04:54:03 rsyslogd: [origin software="rsyslogd" swVersion="4.6.4" x-pid="288" x-info="http://www.rsyslog.com"] rsyslogd was HUPed, type 'lightweight'.
May 18 12:21:15 shutdown[10971]: shutting down for system halt
May 18 12:21:34 kernel: Kernel logging (proc) stopped.
May 18 12:21:34 rsyslogd: [origin software="rsyslogd" swVersion="4.6.4" x-pid="288" x-info="http://www.rsyslog.com"] exiting on signal 15.
May 18 14:09:12 kernel: imklog 4.6.4, log source = /proc/kmsg started.
May 18 14:09:12 rsyslogd: [origin software="rsyslogd" swVersion="4.6.4" x-pid="287" x-info="http://www.rsyslog.com"] (re)start
May 18 15:26:36 kernel: imklog 4.6.4, log source = /proc/kmsg started.
May 18 15:26:36 rsyslogd: [origin software="rsyslogd" swVersion="4.6.4" x-pid="285" x-info="http://www.rsyslog.com"] (re)start
May 19 06:18:39 kernel: imklog 4.6.4, log source = /proc/kmsg started.
May 19 06:18:39 rsyslogd: [origin software="rsyslogd" swVersion="4.6.4" x-pid="285" x-info="http://www.rsyslog.com"] (re)start
^C # Pour interrompre la commande
$
La commande head permet de visualiser, par défaut, les 10 premières lignes d'un flux de données.
Syntaxe
head [-n] [fichiers ...]
Principales options :
-n Affiche les n premières lignes
Exemple
Afficher les 5 premières lignes du fichier /var/log/messages
$ head -5 /var/log/messages
May 13 04:54:06 rsyslogd: [origin software="rsyslogd" swVersion="4.6.4" x-pid="288" x-info="http://www.rsyslog.com"] rsyslogd was HUPed, type 'lightweight'.
May 14 04:54:03 rsyslogd: [origin software="rsyslogd" swVersion="4.6.4" x-pid="288" x-info="http://www.rsyslog.com"] rsyslogd was HUPed, type 'lightweight'.
May 15 04:54:03 rsyslogd: [origin software="rsyslogd" swVersion="4.6.4" x-pid="288" x-info="http://www.rsyslog.com"] rsyslogd was HUPed, type 'lightweight'.
May 15 04:54:03 rsyslogd: [origin software="rsyslogd" swVersion="4.6.4" x-pid="288" x-info="http://www.rsyslog.com"] rsyslogd was HUPed, type 'lightweight'.
May 16 04:54:03 rsyslogd: [origin software="rsyslogd" swVersion="4.6.4" x-pid="288" x-info="http://www.rsyslog.com"] rsyslogd was HUPed, type 'lightweight'.
$
La commande tee récupère un flux de données sur son entrée standard, l'envoie dans le fichier passé en argument et sur la sortie standard. Cela permet d'avoir à la fois le résultat à l'écran et dans un fichier.
Syntaxe
commande | tee [options] fichier
Principales options :
-a Ajoute à la fin de "fichier" si celui-ci existe déjà
Exemple
A partir du fichier /var/log/apache2/access.log, récupérer les lignes datant du 19/05/2012 en les affichant à l'écran et en les enregistrant dans un fichier
$ grep '19/May/2012' /var/log/apache2/access.log | tee 2012_05_19_log_apache
x.x.x.x - - [19/May/2012:14:49:03 +0200] "GET / HTTP/1.1" 200 7226 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0"
x.x.x.x - - [19/May/2012:14:49:04 +0200] "GET /node.css?7 HTTP/1.1" 200 664 "http://quennec.fr/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0"
x.x.x.x - - [19/May/2012:14:49:04 +0200] "GET /defaults.css?7 HTTP/1.1" 200 718 "http://quennec.fr/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0"
...
$
$ head -5 2012_05_19_log_apache
x.x.x.x - - [19/May/2012:14:49:03 +0200] "GET / HTTP/1.1" 200 7226 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0"
x.x.x.x - - [19/May/2012:14:49:04 +0200] "GET /node.css?7 HTTP/1.1" 200 664 "http://quennec.fr/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0"
x.x.x.x - - [19/May/2012:14:49:04 +0200] "GET /defaults.css?7 HTTP/1.1" 200 718 "http://quennec.fr/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0"
x.x.x.x - - [19/May/2012:14:49:05 +0200] "GET /layout.css?7 HTTP/1.1" 200 1444 "http://quennec.fr/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0"
x.x.x.x - - [19/May/2012:14:49:05 +0200] "GET /style.css?7 HTTP/1.1" 200 7648 "http://quennec.fr/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0"
$
La commande nl permet d'afficher un fichier texte en numérotant les lignes. Par défaut, les lignes vides ne sont pas numérotées.
Syntaxe
nl [options] [fichiers ...]
Principales options :
-b a Numéroter toutes les lignes
-b t Ne pas numéroter les lignes vides
Exemple
$ nl fic7
1 erytert
2 e
3 er
4 ..
5 uhy
6 2
7 e_
8 34
9 546
$
Numéroter toutes les lignes, mêmes vides
$ nl -ba fic7
1 erytert
2
3 e
4 er
5 ..
6 uhy
7
8 2
9 e_
10 34
11 546
12
$
La commande pr affiche un texte de manière formatée. Par défaut, chaque page fait 66 lignes, dont 5 lignes d'en-tête et 5 ligne de pied de page.
Syntaxe
pr [options] [fichiers ...]
Quelques options :
-c nb Disposition en nb colonnes
-h texte Ecrire un titre en en-tête
-l nb Nombre de lignes d'une page
Exemples
$ cat depts2012
CP : 01053 DEPT : AIN
CP : 02408 DEPT : AISNE
CP : 03190 DEPT : ALLIER
CP : 04070 DEPT : ALPES-DE-HAUTE-PROVENCE
CP : 05061 DEPT : HAUTES-ALPES
CP : 06088 DEPT : ALPES-MARITIMES
CP : 07186 DEPT : ARDECHE
CP : 08105 DEPT : ARDENNES
CP : 09122 DEPT : ARIEGE
CP : 10387 DEPT : AUBE
CP : 11069 DEPT : AUDE
CP : 12202 DEPT : AVEYRON
CP : 13055 DEPT : BOUCHES-DU-RHONE
CP : 14118 DEPT : CALVADOS
CP : 15014 DEPT : CANTAL
CP : 16015 DEPT : CHARENTE
CP : 17300 DEPT : CHARENTE-MARITIME
CP : 18033 DEPT : CHER
CP : 19272 DEPT : CORREZE
CP : 21231 DEPT : COTE-D'OR
CP : 22278 DEPT : COTES-D'ARMOR
CP : 23096 DEPT : CREUSE
CP : 24322 DEPT : DORDOGNE
CP : 25056 DEPT : DOUBS
CP : 26362 DEPT : DROME
CP : 27229 DEPT : EURE
CP : 28085 DEPT : EURE-ET-LOIR
CP : 29232 DEPT : FINISTERE
CP : 30189 DEPT : GARD
CP : 31555 DEPT : HAUTE-GARONNE
CP : 32013 DEPT : GERS
CP : 33063 DEPT : GIRONDE
CP : 34172 DEPT : HERAULT
CP : 35238 DEPT : ILLE-ET-VILAINE
CP : 36044 DEPT : INDRE
CP : 37261 DEPT : INDRE-ET-LOIRE
CP : 38185 DEPT : ISERE
CP : 39300 DEPT : JURA
CP : 40192 DEPT : LANDES
CP : 41018 DEPT : LOIR-ET-CHER
CP : 42218 DEPT : LOIRE
CP : 43157 DEPT : HAUTE-LOIRE
CP : 44109 DEPT : LOIRE-ATLANTIQUE
CP : 45234 DEPT : LOIRET
CP : 46042 DEPT : LOT
CP : 47001 DEPT : LOT-ET-GARONNE
CP : 48095 DEPT : LOZERE
CP : 49007 DEPT : MAINE-ET-LOIRE
CP : 50502 DEPT : MANCHE
CP : 51108 DEPT : MARNE
CP : 52121 DEPT : HAUTE-MARNE
CP : 53130 DEPT : MAYENNE
CP : 54395 DEPT : MEURTHE-ET-MOSELLE
CP : 55029 DEPT : MEUSE
CP : 56260 DEPT : MORBIHAN
CP : 57463 DEPT : MOSELLE
CP : 58194 DEPT : NIEVRE
CP : 59350 DEPT : NORD
CP : 60057 DEPT : OISE
CP : 61001 DEPT : ORNE
CP : 62041 DEPT : PAS-DE-CALAIS
CP : 63113 DEPT : PUY-DE-DOME
CP : 64445 DEPT : PYRENEES-ATLANTIQUES
CP : 65440 DEPT : HAUTES-PYRENEES
CP : 66136 DEPT : PYRENEES-ORIENTALES
CP : 67482 DEPT : BAS-RHIN
CP : 68066 DEPT : HAUT-RHIN
CP : 69123 DEPT : RHONE
CP : 70550 DEPT : HAUTE-SAONE
CP : 71270 DEPT : SAONE-ET-LOIRE
CP : 72181 DEPT : SARTHE
CP : 73065 DEPT : SAVOIE
CP : 74010 DEPT : HAUTE-SAVOIE
CP : 75056 DEPT : PARIS
CP : 76540 DEPT : SEINE-MARITIME
CP : 77288 DEPT : SEINE-ET-MARNE
CP : 78646 DEPT : YVELINES
CP : 79191 DEPT : DEUX-SEVRES
CP : 80021 DEPT : SOMME
CP : 81004 DEPT : TARN
CP : 82121 DEPT : TARN-ET-GARONNE
CP : 83137 DEPT : VAR
CP : 84007 DEPT : VAUCLUSE
CP : 85191 DEPT : VENDEE
CP : 86194 DEPT : VIENNE
CP : 87085 DEPT : HAUTE-VIENNE
CP : 88160 DEPT : VOSGES
CP : 89024 DEPT : YONNE
CP : 90010 DEPT : TERRITOIRE_DE_BELFORT
CP : 91228 DEPT : ESSONNE
CP : 92050 DEPT : HAUTS-DE-SEINE
CP : 93008 DEPT : SEINE-SAINT-DENIS
CP : 94028 DEPT : VAL-DE-MARNE
CP : 95500 DEPT : VAL-D'OISE
CP : 97105 DEPT : GUADELOUPE
CP : 97209 DEPT : MARTINIQUE
CP : 97302 DEPT : GUYANE
CP : 97411 DEPT : LA_REUNION
CP : 97608 DEPT : MAYOTTE
$
$ pr depts2012 | more
2012-05-19 17:19 depts2012 Page 1
CP : 01053 DEPT : AIN
CP : 02408 DEPT : AISNE
CP : 03190 DEPT : ALLIER
CP : 04070 DEPT : ALPES-DE-HAUTE-PROVENCE
CP : 05061 DEPT : HAUTES-ALPES
CP : 06088 DEPT : ALPES-MARITIMES
CP : 07186 DEPT : ARDECHE
CP : 08105 DEPT : ARDENNES
CP : 09122 DEPT : ARIEGE
CP : 10387 DEPT : AUBE
CP : 11069 DEPT : AUDE
CP : 12202 DEPT : AVEYRON
CP : 13055 DEPT : BOUCHES-DU-RHONE
CP : 14118 DEPT : CALVADOS
CP : 15014 DEPT : CANTAL
CP : 16015 DEPT : CHARENTE
CP : 17300 DEPT : CHARENTE-MARITIME
CP : 18033 DEPT : CHER
CP : 19272 DEPT : CORREZE
...
$
Présentation du fichier en 2 colonnes de 15 lignes par page avec un titre sur chaque page
$ pr -l 15 -c2 -h "Liste des departements" depts2012 | more
2012-05-19 17:19 Liste des departements Page 1
CP : 01053 DEPT : AIN CP : 06088 DEPT : ALPES-MARITI
CP : 02408 DEPT : AISNE CP : 07186 DEPT : ARDECHE
CP : 03190 DEPT : ALLIER CP : 08105 DEPT : ARDENNES
CP : 04070 DEPT : ALPES-DE-HAU CP : 09122 DEPT : ARIEGE
CP : 05061 DEPT : HAUTES-ALPES CP : 10387 DEPT : AUBE
2012-05-19 17:19 Liste des departements Page 2
CP : 11069 DEPT : AUDE CP : 16015 DEPT : CHARENTE
CP : 12202 DEPT : AVEYRON CP : 17300 DEPT : CHARENTE-MAR
CP : 13055 DEPT : BOUCHES-DU-R CP : 18033 DEPT : CHER
CP : 14118 DEPT : CALVADOS CP : 19272 DEPT : CORREZE
CP : 15014 DEPT : CANTAL CP : 21231 DEPT : COTE-D'OR
...
$
La commande wc compte le nombre de lignes, de mots et de caractères.
Syntaxe
wc [OPTION]... [FILE]...
Principales options :
-l Compter le nombre de lignes
-w Compter le nombre de mots
-c Compter le nombre d'octets
-m Compter le nombre de caractères
Exemples
Nombre de lignes, mots et caractères du fichier depts2012
$ wc depts2012
99 594 2769 depts2012
$
Nombre de lignes uniquement
$ wc -l depts2012
99 depts2012
$
Nombre de mots uniquement
$ wc -w depts2012
594 depts2012
$
Nombre de caractères uniquement
$ wc -m depts2012
2769 depts2012
$
Nombre de caractères contenus dans un texte saisi au clavier (attention au saut de ligne ajouté par la commande echo)
$ read texte
ceci est un texte
$ echo "$texte" | wc -m
18 # Le saut de ligne est comptabilisé
$ echo -e "$texte\c" | wc -m
17 # Avec l'option -e et \c le saut de ligne n'est pas comptabilisé
$ echo -n "$texte" | wc -m
17 # Idem mais avec l'option -n
$
La commande cut sert à récupérer des caractères ou des champs d'une ligne.
Syntaxe
Couper par caractères
cut -c3 [fichiers ...] | Le 3ème caractère |
cut -c3-5 [fichiers ...] | Du 3ème au 5ème caractère |
cut -c-3 [fichiers ...] | Jusqu'au 3ème caractère |
cut -c3- [fichiers ...] | A partir du 3ème caractère |
cut -c3,10 [fichiers ...] | Le 3ème et le 10ème caractère |
Couper par champs
cut -dsep -f3 [fichiers ...] | Le 3ème champ |
cut -dsep -f3-5 [fichiers ...] | Du 3ème au 5ème champ |
cut -dsep -f-3 [fichiers ...] | Jusqu'au 3ème champ |
cut -dsep -f3- [fichiers ...] | A partir du 3ème champ |
cut -dsep -f3,10 [fichiers ...] | Le 3ème et le 10ème champ |
L'option -d permet d'exprimer le caractère séparateur de champ. Le caractère séparateur par défaut est la tabulation.
Exemples
Couper les 2 Premiers chiffres d'un code postal
$ echo 44150 | cut -c1-2
44
$
Afficher le 1er, 6ème et 7ème champs des 5 dernières lignes du fichier /etc/passwd
$ tail -5 /etc/passwd | cut -d: -f1,6,7
nobody:/nonexistent:/bin/sh
libuuid:/var/lib/libuuid:/bin/sh
postfix:/var/spool/postfix:/bin/false
sshd:/var/run/sshd:/usr/sbin/nologin
mysql:/var/lib/mysql:/bin/false
$
Si le caractère séparateur est un caractère spécial du shell, il faut le protéger.
$ ligne="val1|val2|val3"
$ echo $ligne | cut -d'|' -f1
val1
$
La commande sort permet de trier les lignes d'un flux de données textes.
Syntaxe
sort [options] -k champs[.car] [options], champ[.car] [options] [fichiers ...]
Principales options :
-b : Option à utiliser lorsque le critère de tri est alphanumérique et que les valeurs dans les champs sont calés à droite et complétés avec des espaces à gauche
-k : champ [.car] [options] , champ [.car] [options] Spécifier le ou les champs à prendre en compte en tant que critère de tri. Le critère de tri peut commencer ou finir à une certaine position de caractère du champ.
-n : Préciser que le critère de tri doit être traité comme valeur numérique et non comme chaine de caractères.
-r : Demander un tri décroissant
-t sep : Préciser le caractère séparateur de champs (espace par défaut)
-u : Suppression des doublons
Exemples
Utilisation du fichier /etc/passwd
$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
lp:x:7:7:lp:/var/spool/lpd:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh
proxy:x:13:13:proxy:/bin:/bin/sh
www-data:x:33:33:www-data:/var/www:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/sh
list:x:38:38:Mailing List Manager:/var/list:/bin/sh
irc:x:39:39:ircd:/var/run/ircd:/bin/sh
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh
nobody:x:65534:65534:nobody:/nonexistent:/bin/sh
libuuid:x:100:101::/var/lib/libuuid:/bin/sh
postfix:x:101:104::/var/spool/postfix:/bin/false
sshd:x:102:65534::/var/run/sshd:/usr/sbin/nologin
mysql:x:103:108:MySQL Server,,,:/var/lib/mysql:/bin/false
$
Trier le fichier sans aucune option.
Le fichier est trié en fonction de la première lettre de chaque ligne.
$ sort /etc/passwd
backup:x:34:34:backup:/var/backups:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
games:x:5:60:games:/usr/games:/bin/sh
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh
irc:x:39:39:ircd:/var/run/ircd:/bin/sh
libuuid:x:100:101::/var/lib/libuuid:/bin/sh
list:x:38:38:Mailing List Manager:/var/list:/bin/sh
lp:x:7:7:lp:/var/spool/lpd:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
mysql:x:103:108:MySQL Server,,,:/var/lib/mysql:/bin/false
news:x:9:9:news:/var/spool/news:/bin/sh
nobody:x:65534:65534:nobody:/nonexistent:/bin/sh
postfix:x:101:104::/var/spool/postfix:/bin/false
proxy:x:13:13:proxy:/bin:/bin/sh
root:x:0:0:root:/root:/bin/bash
sshd:x:102:65534::/var/run/sshd:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
sys:x:3:3:sys:/dev:/bin/sh
uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh
www-data:x:33:33:www-data:/var/www:/bin/sh
$
Trier le fichier sur le 3ème champ (valeurs numériques).
Le tri est alphanumérique.
$ sort -t: -k 3,3 /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh
libuuid:x:100:101::/var/lib/libuuid:/bin/sh
postfix:x:101:104::/var/spool/postfix:/bin/false
sshd:x:102:65534::/var/run/sshd:/usr/sbin/nologin
mysql:x:103:108:MySQL Server,,,:/var/lib/mysql:/bin/false
proxy:x:13:13:proxy:/bin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
www-data:x:33:33:www-data:/var/www:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/sh
list:x:38:38:Mailing List Manager:/var/list:/bin/sh
irc:x:39:39:ircd:/var/run/ircd:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
nobody:x:65534:65534:nobody:/nonexistent:/bin/sh
lp:x:7:7:lp:/var/spool/lpd:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
$
Pour que le tri soit numérique il faut ajouter l'option -n
$ sort -t: -k 3,3 -n /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
lp:x:7:7:lp:/var/spool/lpd:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh
proxy:x:13:13:proxy:/bin:/bin/sh
www-data:x:33:33:www-data:/var/www:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/sh
list:x:38:38:Mailing List Manager:/var/list:/bin/sh
irc:x:39:39:ircd:/var/run/ircd:/bin/sh
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh
libuuid:x:100:101::/var/lib/libuuid:/bin/sh
postfix:x:101:104::/var/spool/postfix:/bin/false
sshd:x:102:65534::/var/run/sshd:/usr/sbin/nologin
mysql:x:103:108:MySQL Server,,,:/var/lib/mysql:/bin/false
nobody:x:65534:65534:nobody:/nonexistent:/bin/sh
$
Exemple de tri sur un fichier dont le champ servant de critère de tri est alphanumérique et complété avec des espaces à gauche.
$ cat listeFic
-rw-r--r-- 1 root root 17 May 17 21:31 fic1
-rw-r--r-- 1 root root 17 May 17 21:36 fic4
-rw-r--r-- 1 root root 23 May 17 21:33 fic2
-rw-r--r-- 1 root root 35 May 19 15:02 fic7
-rw-r--r-- 1 root root 36 May 17 21:52 fic5
-rw-r--r-- 1 root root 40 May 17 21:33 fic3
-rw-r--r-- 1 root root 48 May 19 17:59 fic8
-rw-r--r-- 1 root root 74 May 17 22:01 fic6.txt
$
Tri sur le champ 9. Valeurs alphanumériques complétées avec des espaces à gauche. Sans l'option -b, le tri est mal réalisé.
$ sort -k 9,9 listeFic
-rw-r--r-- 1 root root 17 May 17 21:31 fic1
-rw-r--r-- 1 root root 23 May 17 21:33 fic2
-rw-r--r-- 1 root root 40 May 17 21:33 fic3
-rw-r--r-- 1 root root 17 May 17 21:36 fic4
-rw-r--r-- 1 root root 36 May 17 21:52 fic5
-rw-r--r-- 1 root root 35 May 19 15:02 fic7
-rw-r--r-- 1 root root 48 May 19 17:59 fic8
-rw-r--r-- 1 root root 74 May 17 22:01 fic6.txt
$
Idem mais avec l'option -b
$ sort -b -k 9,9 listeFic
-rw-r--r-- 1 root root 17 May 17 21:31 fic1
-rw-r--r-- 1 root root 23 May 17 21:33 fic2
-rw-r--r-- 1 root root 40 May 17 21:33 fic3
-rw-r--r-- 1 root root 17 May 17 21:36 fic4
-rw-r--r-- 1 root root 36 May 17 21:52 fic5
-rw-r--r-- 1 root root 74 May 17 22:01 fic6.txt
-rw-r--r-- 1 root root 35 May 19 15:02 fic7
-rw-r--r-- 1 root root 48 May 19 17:59 fic8
$
Utilisation de 2 critères de tri: Tri sur le champ 7 (numérique) et sur le champ 9 (alphanumérique)
$ sort -k 7n,7 -k 9b,9 listeFic
-rw-r--r-- 1 root root 74 May 15 22:01 fic6.txt
-rw-r--r-- 1 root root 35 May 15 15:02 fic7
-rw-r--r-- 1 root root 17 May 17 21:31 fic1
-rw-r--r-- 1 root root 23 May 17 21:33 fic2
-rw-r--r-- 1 root root 40 May 17 21:33 fic3
-rw-r--r-- 1 root root 17 May 17 21:36 fic4
-rw-r--r-- 1 root root 36 May 17 21:52 fic5
-rw-r--r-- 1 root root 48 May 19 17:59 fic8
$
Trier un fichier suivant les mois de l'année
$ cat fic91
April
August
December
February
January
July
June
March
May
November
October
September
$
$ sort -M fic91
January
February
March
April
May
June
July
August
September
October
November
December
$
La commande paste concatène les lignes de même niveau des fichiers passés en argument. Avec l'option -s, chaque fichier est traité de manière indépendante et verra toutes ses lignes concaténées en une seule. Les éléments concaténés sont séparés par une tabulation.
Syntaxe
paste [options] [fichiers ...]
Principales options :
-s : Concaténer toutes les lignes en une seule
-d listesep : Les caractères cités dans listesep seront utilisés pour séparer les champs en sortie
Exemple
Exemple avec 2 fichiers contenant les dépenses d'un ménage pour le mois de janvier 2012 et février 2012. Les catégories sont mentionnées dans le même ordre.
$ cat janvier2012
Alimentation 50.00
Eau 25.00
Electricite 123.50
Loyer 456.90
Assurances 234.00
$ cat fevrier2012
Alimentation 67.00
Eau 34.00
Electricite 156.00
Loyer 456.90
Assurances 225.00
$
Mettre sur la même ligne les montants de chaque catégorie.
$ paste janvier2012 fevrier2012
Alimentation 50.00 Alimentation 67.00
Eau 25.00 Eau 34.00
Electricite 123.50 Electricite 156.00
Loyer 456.90 Loyer 456.90
Assurances 234.00 Assurances 225.00
$
Retirer la 3ème colonne et ajouter des en-têtes de colonnes et le total pour chaque mois.
$ paste janvier2012 fevrier2012 | awk 'BEGIN{printf("%-15s\t%7s\t%7s\n","POSTE","JANVIER","FEVRIER")}{printf("%-15s\t%7.2f\t%7.2f\n",$1,$2,$4);jan+=$2;fev+=$4}END{printf("%-15s\t%7.2f\t%7.2f\n","TOTAL",jan,fev)}'
POSTE JANVIER FEVRIER
Alimentation 50.00 67.00
Eau 25.00 34.00
Electricite 123.50 156.00
Loyer 456.90 456.90
Assurances 234.00 225.00
TOTAL 889.40 938.90
$
Concaténer toutes les lignes en une seule.
$ paste -s janvier2012 fevrier2012
Alimentation 50.00 Eau 25.00 Electricite 123.50 Loyer 456.90 Assurances 234.00
Alimentation 67.00 Eau 34.00 Electricite 156.00 Loyer 456.90 Assurances 225.00
$
La commande split permet d'éclater un fichier en fragments. Chaque fragment étant stocké dans des fichiers nommés PREFIXEaa, PREFIXEab, ... PREFIXE ayant pour valeur par défaut "x". Si aucun nom de fichier n'est spécifié, l'entrée standard est utilisée.
Syntaxe
split [options] [fichiers ... [prefixe]]
Principales options :
-b nb : Le fichier est éclaté tous les "nb" octets
-l nb : Le fichier est éclaté toutes les "nb" lignes
Exemples
Exemple avec un fichier contenant 9 lignes
$ cat fic10
ligne1
ligne2
ligne3
ligne4
ligne5
ligne6
ligne7
ligne8
ligne9
$
Eclater le fichier en différents fichiers de 3 lignes chacuns. Par défaut, chaque fichier généré sera préfixé par la lettre "x".
$ split -l3 fic10
$ ls -l x*
-rw-r--r-- 1 root root 21 May 23 08:56 xaa
-rw-r--r-- 1 root root 21 May 23 08:56 xab
-rw-r--r-- 1 root root 21 May 23 08:56 xac
$ cat xaa
ligne1
ligne2
ligne3
$ cat xab
ligne4
ligne5
ligne6
$ cat xac
ligne7
ligne8
ligne9
$
Modifier le préfixe des fichiers générés.
$ split -l3 fic10 fichier
$ ls -l fichier*
-rw-r--r-- 1 root root 21 May 23 08:58 fichieraa
-rw-r--r-- 1 root root 21 May 23 08:58 fichierab
-rw-r--r-- 1 root root 21 May 23 08:58 fichierac
$
La commande tr permet d'appliquer un traitement sur certains caractères d'un flux de données : suppression, substitutions ... Cette commande exploite uniquement les données arrivant sur l'entrée standard.
Syntaxe
tr [options] ensemble1 [ensemble2]
Principale option :
[-d caractères] : La liste des caractères qui doivent être supprimés du flux de données.
Deux ensembles de caractères doivent être spécifiés. Chaque ensemble comporte le même nombre de caractères. Tout caractère de ensemble1 trouvé dans le flux de données est substitué par le caractère de même position situé dans ensemble2.
Exemples
La chaine abcd est traitée : chaque caractère b est remplacé par 2 et chaque caractère d est remplacé par 4.
$ echo abcd | tr bd 24
a2c4
$
Il est possible d'utiliser la notion d'intervalles de caractères en utilisant des crochets. Ici chaque minuscule est remplacée par une majuscule correspondante :
$ echo abcd | tr "[a-z]" "[A-Z]"
ABCD
$
Pour traiter un fichier, il faut utiliser la redirection :
$ cat fic1
ceci est un test
$ tr "[a-z]" "[A-Z]" < fic1
CECI EST UN TEST
$
L'option -d permet de supprimer certains caractères du flux de données.
Exemples
Transformation d'un fichier au format DOS (fin de lignes "\r\n") en un format UNIX ("\n"). Retrait du caractère "\r" :
$ od -c fic100
0000000 c e c i e s t u n t e s t
0000020 \r \n
0000022
$ tr -d '\r' < fic100 > fic101
$ od -c fic101
0000000 c e c i e s t u n t e s t
0000020 \n
0000021
$
En ajoutant l'option -c à l'option -d, la commande supprime tous les caractères non présents dans la liste passée en argument :
$ echo "Linux Pratique HS N°26 – Février/Mars 2013 – En kiosque" | tr -dc a-zA-Z; echo
LinuxPratiqueHSNFvrierMarsEnkiosque
La dernière commande echo permet uniquement d'afficher un retour à la ligne.
La commande uniq permet de dédoublonner les lignes d'un fichier. Seules les lignes identiques consécutives sont traitées. Elle s'utilise le plus souvent à la suite de la commande sort. Le résultat est stocké dans un fichier de sortie, si celui-ci est spécifié, sur la sortie standard dans le cas contraire.
Syntaxe
uniq [options] [fichier_entree [fichier_sortie]]
Principales options :
-d : Affichage des doublons
-c : Comptage des doublons
Exemples
Le fichier fic20 contient des lignes en double
$ cat fic20
ceci est un test
ceci est un test
ceci est un test
ceci est un test
ceci est un autre test
ceci est un test
ceci est un autre test
ceci est un test
ceci est un test
et un autre test
ceci est un fichier
$
Le fichier doit être trié pour que les lignes identiques soient consécutives :
$ sort fic20
ceci est un autre test
ceci est un autre test
ceci est un fichier
ceci est un test
ceci est un test
ceci est un test
ceci est un test
ceci est un test
ceci est un test
ceci est un test
et un autre test
$
Et enfin, suppression des doublons :
$ sort fic20 | uniq
ceci est un autre test
ceci est un fichier
ceci est un test
ceci est un test
ceci est un test
et un autre test
$
Résultat identique avec la commande sort et l'option -u :
$ sort -u fic20
ceci est un autre test
ceci est un fichier
ceci est un test
ceci est un test
ceci est un test
et un autre test
$
Afficher devant chaque ligne son nombre d'occurences dans le fichier :
$ sort fic20 | uniq -c
2 ceci est un autre test
1 ceci est un fichier
5 ceci est un test
1 ceci est un test
1 ceci est un test
1 et un autre test
$
Afficher uniquement les lignes ayant des doublons :
$ sort fic20 | uniq -d
ceci est un autre test
ceci est un test
$
Combinées les options -c et -d :
$ sort fic20 | uniq -cd
2 ceci est un autre test
5 ceci est un test
$
Afficher les lignes uniques :
$ sort fic20 | uniq -u
ceci est un fichier
ceci est un test
ceci est un test
et un autre test
$ sort fic20 | uniq -cu
1 ceci est un fichier
1 ceci est un test
1 ceci est un test
1 et un autre test
$
Les commandes gzip/gunzip, bzip2/bunzip2 compressent/décompressent chaque fichier passé en argument sur la ligne de commande. La commande bzip2 possède un meilleur taux de compression. Ces commandes se trouvent en standard sur les systèmes Linux et peuvent s'installer sur les systèmes UNIX si elles ne sont pas déjà présentes. La commande gzip produit l'extension .gz et la commande bzip2 produit l'extension .bz2.
Syntaxe de gzip
Compression :
gzip [options] [fichiers ...]
Décompression :
gunzip [options] [fichiers ...]
zcat [options] [fichiers ...]
Principales options :
-c : Envoie le résultat sur la sortie standard. La commande gunzip -c est équivalente à la commande zcat.
-t : Tester la validité de l'archive.
Si le nom de fichier est omis, les données à traiter sont lues sur l'entrée standard.
Exemple
Compression du fichier mon_fichier4. L'original est remplacé par le fichier compressé.
$ ls -lh mon_fichier4
-rw-r--r-- 1 root root 6,6M 25 mai 16:36 mon_fichier4
$ gzip mon_fichier4
$ ls -lh mon_fichier4.gz
-rw-r--r-- 1 root root 2,1M 25 mai 16:36 mon_fichier4.gz
$
Décompression. Le fichier d'origine est restitué et remplace le fichier compressé.
$ gunzip mon_fichier4.gz
$ ls -lh mon_fichier4*
-rw-r--r-- 1 root root 6,6M 25 mai 16:36 mon_fichier4
$
Compression du fichier avec envoi du flux sur la sortie standard. Cette méthode permet de conserver le fichier d'origine.
$ gzip -c mon_fichier4 > mon_fichier4.gz
$ ls -lh mon_fichier4*
-rw-r--r-- 1 root root 6,6M 25 mai 16:36 mon_fichier4
-rw-r--r-- 1 root root 2,1M 25 mai 16:42 mon_fichier4.gz
$
Décompressé en conservant le fichier compressé.
$ gunzip -c mon_fichier4.gz > mon_fichier5
$ ls -lh mon_fichier*
-rw-r--r-- 1 root root 6,6M 25 mai 16:36 mon_fichier4
-rw-r--r-- 1 root root 2,1M 25 mai 16:42 mon_fichier4.gz
-rw-r--r-- 1 root root 6,6M 25 mai 16:44 mon_fichier5
$
Idem mais avec la commande zcat.
$ zcat mon_fichier4.gz > mon_fichier6
$ ls -lh mon_fichier*
-rw-r--r-- 1 root root 6,6M 25 mai 16:36 mon_fichier4
-rw-r--r-- 1 root root 2,1M 25 mai 16:42 mon_fichier4.gz
-rw-r--r-- 1 root root 6,6M 25 mai 16:44 mon_fichier5
-rw-r--r-- 1 root root 6,6M 25 mai 16:46 mon_fichier6
$
Les commandes bzip2, bunzip2 et bzcat fonctionnent de manière similaire avec une légère différence au niveau des options.
Syntaxe de bzip2
Compression :
bzip2 [options] [fichiers ...]
Décompression :
bunzip2 [fichiers ...]
bzip2 -d [options] [fichiers ...]
bzcat [options] [fichiers ...]
Principales options :
-c : Envoie le résultat sur la sortie standard. La commande bzip2 -dc est équivalente à la commande bzcat.
-d : Décompression
-t : Tester la validité de l'archive.
Exemple
Compression du fichier mon_fichier4. La compression avec bzip2 est meilleure qu'avec gzip.
$ ls -lh mon_fichier*
-rw-r--r-- 1 root root 6,6M 25 mai 16:36 mon_fichier4
-rw-r--r-- 1 root root 2,1M 25 mai 16:42 mon_fichier4.gz
-rw-r--r-- 1 root root 6,6M 25 mai 16:44 mon_fichier5
-rw-r--r-- 1 root root 6,6M 25 mai 16:46 mon_fichier6
$ bzip2 -c mon_fichier4 > mon_fichier4.bz2
$ ls -lh mon_fichier*
-rw-r--r-- 1 root root 6,6M 25 mai 16:36 mon_fichier4
-rw-r--r-- 1 root root 1,2M 25 mai 16:54 mon_fichier4.bz2
-rw-r--r-- 1 root root 2,1M 25 mai 16:42 mon_fichier4.gz
-rw-r--r-- 1 root root 6,6M 25 mai 16:44 mon_fichier5
-rw-r--r-- 1 root root 6,6M 25 mai 16:46 mon_fichier6
$
Analyse des différentes compressions
$ wc -c mon_fichier4
6903921 mon_fichier4
$ wc -m mon_fichier4
6903921 mon_fichier4
$ ls -l mon_fichier*
-rw-r--r-- 1 root root 6903921 25 mai 16:36 mon_fichier4
-rw-r--r-- 1 root root 1207370 25 mai 16:54 mon_fichier4.bz2
-rw-r--r-- 1 root root 2129319 25 mai 16:42 mon_fichier4.gz
-rw-r--r-- 1 root root 6903921 25 mai 16:44 mon_fichier5
-rw-r--r-- 1 root root 6903921 25 mai 16:46 mon_fichier6
$
Test réalisé avec un fichier contenant uniquement des caractères.
Le fichier mon_fichier4 contient 6 903 921 caractères et par conséquent une taille de 6 903 921 octets.
Compression avec gzip : Le fichier a été réduit à une taille de 2 129 319 octets. Ce qui représente une diminution de 69,16 %
Compression avec bzip2 : Le fichier a été réduit à une taille de 1 207 370 octets. Ce qui représente une diminution de 82,51%
La commande tar permet de créer une archive à partir d'un ou plusieurs fichiers. Si le fichier est un répertoire, il sera archivé avec sa sous-arborescence.
Syntaxe
Création d'une archive :
tar -c [-zv] -f archive fichiers_a_archiver ...
Vérification d'une archive :
tar -t [-zv] -f archive [fichiers_a_verifier ...]
Extraction d'une archive :
tar -x [-zv] -f archive [fichiers_a_extraire ...]
Principales options :
-c : Création d'une archive
-t : Vérification d'une archive
-x : Extraction d'une archive
-f archive.tar : Nom de l'archive à créer, vérifier ou extraire
-f - : Dans le cas d'une création, le contenu de l'archive est envoyé sur la sortie standard. En extraction et vérification, le contenu de l'archive est attendu sur l'entrée standard
-v : Mode verbeux
-z : Sous Linux uniquement : permet de gérer en plus la compression avec gzip
-j : Compression avec bzip2
Exemples
Archivage et compression du dossier dossier_a_sauvegarder. La commande tar envoi le contenu de l'archive à la commande gzip via un pipe et qui compresse l'archive dans un fichier dossier_a_sauvegarder.tar.gz
$ ls -R dossier_a_sauvegarder
dossier_a_sauvegarder:
aZerty Bonjour Coucou help history last monscript pays2011.txt.1 piwik1 piwik2 result ronan ronan2 ronan3 search test
$ tar -cvf - dossier_a_sauvegarder | gzip -c > dossier_a_sauvegarder.tar.gz
dossier_a_sauvegarder/
dossier_a_sauvegarder/ronan2
dossier_a_sauvegarder/last
dossier_a_sauvegarder/search
dossier_a_sauvegarder/piwik2
dossier_a_sauvegarder/ronan3
dossier_a_sauvegarder/result
dossier_a_sauvegarder/help
dossier_a_sauvegarder/history
dossier_a_sauvegarder/Coucou
dossier_a_sauvegarder/pays2011.txt.1
dossier_a_sauvegarder/monscript
dossier_a_sauvegarder/ronan
dossier_a_sauvegarder/test
dossier_a_sauvegarder/Bonjour
dossier_a_sauvegarder/piwik1
dossier_a_sauvegarder/aZerty
$ ls -l dossier_a_sauvegarder.tar.gz
-rw-r--r-- 1 root root 369562 25 mai 17:30 dossier_a_sauvegarder.tar.gz
$
Décompression et extraction. La commande gunzip décompresse le fichier et envoie le résultat à la commande tar qui extrait tout le contenu de l'archive.
$ gunzip -c dossier_a_sauvegarder.tar.gz | tar -xvf -
dossier_a_sauvegarder/
dossier_a_sauvegarder/ronan2
dossier_a_sauvegarder/last
dossier_a_sauvegarder/search
dossier_a_sauvegarder/piwik2
dossier_a_sauvegarder/ronan3
dossier_a_sauvegarder/result
dossier_a_sauvegarder/help
dossier_a_sauvegarder/history
dossier_a_sauvegarder/Coucou
dossier_a_sauvegarder/pays2011.txt.1
dossier_a_sauvegarder/monscript
dossier_a_sauvegarder/ronan
dossier_a_sauvegarder/test
dossier_a_sauvegarder/Bonjour
dossier_a_sauvegarder/piwik1
dossier_a_sauvegarder/aZerty
$
Lister le contenu d'une archive
$ gunzip -c dossier_a_sauvegarder.tar.gz | tar -tf -
dossier_a_sauvegarder/
dossier_a_sauvegarder/ronan2
dossier_a_sauvegarder/last
dossier_a_sauvegarder/search
dossier_a_sauvegarder/piwik2
dossier_a_sauvegarder/ronan3
dossier_a_sauvegarder/result
dossier_a_sauvegarder/help
dossier_a_sauvegarder/history
dossier_a_sauvegarder/Coucou
dossier_a_sauvegarder/pays2011.txt.1
dossier_a_sauvegarder/monscript
dossier_a_sauvegarder/ronan
dossier_a_sauvegarder/test
dossier_a_sauvegarder/Bonjour
dossier_a_sauvegarder/piwik1
dossier_a_sauvegarder/aZerty
$
Archivage et compression en utilisant l'option -z
$ tar -cvzf monArchive.tar.gz dossier_a_sauvegarder
dossier_a_sauvegarder/
dossier_a_sauvegarder/ronan2
dossier_a_sauvegarder/last
dossier_a_sauvegarder/search
dossier_a_sauvegarder/piwik2
dossier_a_sauvegarder/ronan3
dossier_a_sauvegarder/result
dossier_a_sauvegarder/help
dossier_a_sauvegarder/history
dossier_a_sauvegarder/Coucou
dossier_a_sauvegarder/pays2011.txt.1
dossier_a_sauvegarder/monscript
dossier_a_sauvegarder/ronan
dossier_a_sauvegarder/test
dossier_a_sauvegarder/Bonjour
dossier_a_sauvegarder/piwik1
dossier_a_sauvegarder/aZerty
$
Idem pour lister le contenu de l'archive. En fait, l'option -z n'est pas obligatoire. Que l'archive soit compressée ou pas les options -tf suffisent.
$ tar -tf monArchive.tar.gz
dossier_a_sauvegarder/
dossier_a_sauvegarder/ronan2
dossier_a_sauvegarder/last
dossier_a_sauvegarder/search
dossier_a_sauvegarder/piwik2
dossier_a_sauvegarder/ronan3
dossier_a_sauvegarder/result
dossier_a_sauvegarder/help
dossier_a_sauvegarder/history
dossier_a_sauvegarder/Coucou
dossier_a_sauvegarder/pays2011.txt.1
dossier_a_sauvegarder/monscript
dossier_a_sauvegarder/ronan
dossier_a_sauvegarder/test
dossier_a_sauvegarder/Bonjour
dossier_a_sauvegarder/piwik1
dossier_a_sauvegarder/aZerty
$
Ajouter un fichier à une archive existante en 3 étapes.
1 - Décompression (un fichier ne peut être ajouté à une archive compressée
$ gunzip monArchive.tar.gz
2 - Ajout du fichier xam à l'archive
$ tar -rf monArchive.tar xam
3 - Compression de l'archive
$ gzip monArchive.tar
Vérifier les différences entre le contenu de l'archive tar et les fichiers sources. Mettre à jour si nécessaire.
1 - Décompression de l'archive
$ gunzip monArchive.tar.gz
2 - Comparaison de l'archive avec les fichiers sources et affichage des différences existantes
$ tar -df monArchive.tar
dossier_a_sauvegarder/aZerty: La date de modification est différente.
dossier_a_sauvegarder/aZerty: La taille est différente.
$
3 - Suppresion du fichier ou des fichiers ayant des différences
$ tar --delete -f monArchive.tar dossier_a_sauvegarder/aZerty
4 - Mise à jour des fichiers en cas de différences trouvées.
$ tar -uf monArchive.tar dossier_a_sauvegarder
5 - Compression de l'archive
$ gzip monArchive.tar
La commande cpio permet également de faire des archives. Contrairement à la commande tar, elle n'est pas récursive. Tous les noms de fichiers entrant dans la composition de l'archive doivent être lus sur l'entrée standard. L'archive est envoyée sur la sortie standard. La commande est presque toujours utilisée derrière un tube lui-même précédé de la commande find qui permet de générer les noms de fichiers souhaités.
En vérification et restauration, l'archive à traiter est attendue sur l'entrée standard.
Syntaxe
Création d'une archive :
find . | cpio -o [-cv] > archive
Vérification d'une archive :
cpio -it [-cv] < archive [fichiers_a_verifier ...]
Extraction d'une archive :
cpio -i [-cdv] < archive [fichiers_a_extraire ...]
Principales options :
-c : Création/vérification/extraction d'une archive ayant un format d'en-tête d'archive portable entre les systèmes UNIX
-d : Extraction avec création des répertoires s'ils n'existent pas
-i : Extraction d'une archive
-it : Vérification d'une archive
-o : Création d'une archive
-v : Mode verbeux
Exemples
Archivage du dossier dossier_a_sauvegarder
$ find dossier_a_sauvegarder
dossier_a_sauvegarder
dossier_a_sauvegarder/ronan2
dossier_a_sauvegarder/last
dossier_a_sauvegarder/search
dossier_a_sauvegarder/piwik2
dossier_a_sauvegarder/ronan3
dossier_a_sauvegarder/result
dossier_a_sauvegarder/help
dossier_a_sauvegarder/history
dossier_a_sauvegarder/Coucou
dossier_a_sauvegarder/pays2011.txt.1
dossier_a_sauvegarder/monscript
dossier_a_sauvegarder/ronan
dossier_a_sauvegarder/test
dossier_a_sauvegarder/Bonjour
dossier_a_sauvegarder/piwik1
dossier_a_sauvegarder/aZerty
$ find dossier_a_sauvegarder | cpio -ocv > monArchive.cpio
dossier_a_sauvegarder
dossier_a_sauvegarder/ronan2
dossier_a_sauvegarder/last
dossier_a_sauvegarder/search
dossier_a_sauvegarder/piwik2
dossier_a_sauvegarder/ronan3
dossier_a_sauvegarder/result
dossier_a_sauvegarder/help
dossier_a_sauvegarder/history
dossier_a_sauvegarder/Coucou
dossier_a_sauvegarder/pays2011.txt.1
dossier_a_sauvegarder/monscript
dossier_a_sauvegarder/ronan
dossier_a_sauvegarder/test
dossier_a_sauvegarder/Bonjour
dossier_a_sauvegarder/piwik1
dossier_a_sauvegarder/aZerty
6674 blocs
$
Vérification de l'archive
$ cpio -icvt < monArchive.cpio
drwxr-xr-x 2 root root 0 Apr 17 13:15 dossier_a_sauvegarder
-rw-r--r-- 1 root root 281 Apr 17 08:46 dossier_a_sauvegarder/ronan2
-rw-r--r-- 1 root root 3171822 Apr 17 08:46 dossier_a_sauvegarder/last
-rw-r--r-- 1 root root 195732 Apr 17 08:46 dossier_a_sauvegarder/search
-rw-r--r-- 1 root root 622 Apr 17 08:46 dossier_a_sauvegarder/piwik2
-rw-r--r-- 1 root root 281 Apr 17 08:46 dossier_a_sauvegarder/ronan3
-rw-r--r-- 1 root root 116 Apr 17 08:46 dossier_a_sauvegarder/result
-rw-r--r-- 1 root root 3083 Apr 17 08:46 dossier_a_sauvegarder/help
-rw-r--r-- 1 root root 26000 Apr 17 08:46 dossier_a_sauvegarder/history
-rw-r--r-- 1 root root 7 Apr 17 08:46 dossier_a_sauvegarder/Coucou
-rw-r--r-- 1 root root 15667 Apr 17 08:46 dossier_a_sauvegarder/pays2011.txt.1
-rw-r--r-- 1 root root 10 Apr 17 08:46 dossier_a_sauvegarder/monscript
-rw------- 1 root root 281 Apr 17 08:46 dossier_a_sauvegarder/ronan
-rw-r--r-- 1 root root 387 Apr 17 08:46 dossier_a_sauvegarder/test
-rw-r--r-- 1 root root 0 Apr 17 08:46 dossier_a_sauvegarder/Bonjour
-rw-r--r-- 1 root root 622 Apr 17 08:46 dossier_a_sauvegarder/piwik1
-rw-r--r-- 1 root root 36 May 25 18:11 dossier_a_sauvegarder/aZerty
6674 blocs
$
Création d'une archive cpio compressée avec bzip2
$ find dossier_a_sauvegarder | cpio -ocv | bzip2 -c > monArchive.cpio.bz2
dossier_a_sauvegarder
dossier_a_sauvegarder/ronan2
dossier_a_sauvegarder/last
dossier_a_sauvegarder/search
dossier_a_sauvegarder/piwik2
dossier_a_sauvegarder/ronan3
dossier_a_sauvegarder/result
dossier_a_sauvegarder/help
dossier_a_sauvegarder/history
dossier_a_sauvegarder/Coucou
dossier_a_sauvegarder/pays2011.txt.1
dossier_a_sauvegarder/monscript
dossier_a_sauvegarder/ronan
dossier_a_sauvegarder/test
dossier_a_sauvegarder/Bonjour
dossier_a_sauvegarder/piwik1
dossier_a_sauvegarder/aZerty
6674 blocs
$
Décompression et extraction de l'archive
$ mkdir tmp
$ cp monArchive.cpio.bz2 tmp
$ cd tmp
$ ll
total 276
drwxr-xr-x 2 root root 4096 26 mai 08:59 .
drwx------ 12 root root 4096 26 mai 08:58 ..
-rw-r--r-- 1 root root 266276 26 mai 08:59 monArchive.cpio.bz2
$ bzip2 -dc monArchive.cpio.bz2 | cpio -icvd
dossier_a_sauvegarder
dossier_a_sauvegarder/ronan2
dossier_a_sauvegarder/last
dossier_a_sauvegarder/search
dossier_a_sauvegarder/piwik2
dossier_a_sauvegarder/ronan3
dossier_a_sauvegarder/result
dossier_a_sauvegarder/help
dossier_a_sauvegarder/history
dossier_a_sauvegarder/Coucou
dossier_a_sauvegarder/pays2011.txt.1
dossier_a_sauvegarder/monscript
dossier_a_sauvegarder/ronan
dossier_a_sauvegarder/test
dossier_a_sauvegarder/Bonjour
dossier_a_sauvegarder/piwik1
dossier_a_sauvegarder/aZerty
6674 blocs
$ ll
total 280
drwxr-xr-x 3 root root 4096 26 mai 08:59 .
drwx------ 12 root root 4096 26 mai 08:58 ..
drwxr-xr-x 2 root root 4096 26 mai 08:59 dossier_a_sauvegarder
-rw-r--r-- 1 root root 266276 26 mai 08:59 monArchive.cpio.bz2
$ ll dossier_a_sauvegarder/
total 3396
drwxr-xr-x 2 root root 4096 26 mai 08:59 .
drwxr-xr-x 3 root root 4096 26 mai 08:59 ..
-rw-r--r-- 1 root root 36 26 mai 08:59 aZerty
-rw-r--r-- 1 root root 0 26 mai 08:59 Bonjour
-rw-r--r-- 1 root root 7 26 mai 08:59 Coucou
-rw-r--r-- 1 root root 3083 26 mai 08:59 help
-rw-r--r-- 1 root root 26000 26 mai 08:59 history
-rw-r--r-- 1 root root 3171822 26 mai 08:59 last
-rw-r--r-- 1 root root 10 26 mai 08:59 monscript
-rw-r--r-- 1 root root 15667 26 mai 08:59 pays2011.txt.1
-rw-r--r-- 1 root root 622 26 mai 08:59 piwik1
-rw-r--r-- 1 root root 622 26 mai 08:59 piwik2
-rw-r--r-- 1 root root 116 26 mai 08:59 result
-rw------- 1 root root 281 26 mai 08:59 ronan
-rw-r--r-- 1 root root 281 26 mai 08:59 ronan2
-rw-r--r-- 1 root root 281 26 mai 08:59 ronan3
-rw-r--r-- 1 root root 195732 26 mai 08:59 search
-rw-r--r-- 1 root root 387 26 mai 08:59 test
$
La commande dd réalise une copie physique d'un flux d'entrée vers un flux de sortie. Chaque octet souhaité du flux d'entrée est copié vers le flux de sortie, indépendamment de ce que représente la donnée.
Syntaxe
dd [if=fichier_entree] [of=fichier_sortie] [ibs=nboctets] [obs=nboctets] [bs=nboctets] [skip=nbblocs] [seek=nbblocs] [count=nbblocs]
Principales options :
if=fichier_entree : Fichier à traiter. Si aucun fichier n'est spécifié, l'entrée standard est traité.
of=fichier_sortie : Fichier de sortie. Si aucun fichier n'est spécifié, la sortie standard est utilisée.
ibs=nboctets : Traiter les données en entrée par blocs de nboctets octets (défaut : 512 octets).
obs=nboctets : Ecrire les données en sortie par blocs de nboctets octets (défaut : 512 octets).
bs=nboctets : Traiter les données d'entrée et de sortie par bloc de nboctets.
skip=nbblocs : Sauter nbblocs en entrée avant de commencer le traitement.
seek=nbblocs : En sortie, écrire à partir du bloc nbblocs.
count=nbblocs : Ecrire uniquement nbblocs de l'entrée vers la sortie.
Exemples
Copie du disque /dev/sda sur le disque /dev/sdb par blocs de 8ko
$ fdisk -l
Disque /dev/sda: 8589 Mo, 8589934592 octets
255 têtes, 63 secteurs/piste, 1044 cylindres
Unités = cylindres de 16065 * 512 = 8225280 octets
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Identifiant de disque : 0x00040afc
Périphérique Amorce Début Fin Blocs Id Système
/dev/sda1 * 1 994 7977984 83 Linux
La partition 1 ne se termine pas sur une frontière de cylindre.
/dev/sda2 994 1045 407553 5 Etendue
/dev/sda5 994 1045 407552 82 Linux swap / Solaris
Disque /dev/sdb: 8589 Mo, 8589934592 octets
255 têtes, 63 secteurs/piste, 1044 cylindres
Unités = cylindres de 16065 * 512 = 8225280 octets
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Identifiant de disque : 0x00000000
Le disque /dev/sdb ne contient pas une table de partition valide
$ dd if=/dev/sda of=/dev/sdb bs=8k
1048576+0 enregistrements lus
1048576+0 enregistrements écrits
8589934592 octets (8,6 GB) copiés, 859,097 s, 10,0 MB/s
$
$ fdisk -l
Disque /dev/sda: 8589 Mo, 8589934592 octets
255 têtes, 63 secteurs/piste, 1044 cylindres
Unités = cylindres de 16065 * 512 = 8225280 octets
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Identifiant de disque : 0x00040afc
Périphérique Amorce Début Fin Blocs Id Système
/dev/sda1 * 1 994 7977984 83 Linux
La partition 1 ne se termine pas sur une frontière de cylindre.
/dev/sda2 994 1045 407553 5 Etendue
/dev/sda5 994 1045 407552 82 Linux swap / Solaris
Disque /dev/sdb: 8589 Mo, 8589934592 octets
255 têtes, 63 secteurs/piste, 1044 cylindres
Unités = cylindres de 16065 * 512 = 8225280 octets
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Identifiant de disque : 0x00040afc
Périphérique Amorce Début Fin Blocs Id Système
/dev/sdb1 * 1 994 7977984 83 Linux
La partition 1 ne se termine pas sur une frontière de cylindre.
/dev/sdb2 994 1045 407553 5 Etendue
/dev/sdb5 994 1045 407552 82 Linux swap / Solaris
Idem mais sur un disque sur une machine distante
$ dd if=/dev/sda | ssh 192.168.1.19 dd of=/dev/sdb bs=8k
Supprimer les 5 premiers octets du fichier fic1
$ cat fic1
ceci est un test
$ od -c fic1
0000000 c e c i e s t u n t e s t
0000020 \n
0000021
$ dd bs=1 skip=5 if=fic1 of=fic11
12+0 enregistrements lus
12+0 enregistrements écrits
12 octets (12 B) copiés, 0,00010661 s, 113 kB/s
$ cat fic11
est un test
$ od -c fic11
0000000 e s t u n t e s t \n
0000014
$
Retirer le dernier octet d'un fichier de 6 903 921 octets. La taille du bloc est fixée à 6 903 920 octets. Le nombre de blocs traités est de 1
$ ls -l mon_fichier4
-rw-r--r-- 1 root root 6903921 25 mai 16:36 mon_fichier4
$ dd if=mon_fichier4 of=mon_fichier41 bs=6903920 count=1
1+0 enregistrements lus
1+0 enregistrements écrits
6903920 octets (6,9 MB) copiés, 0,183292 s, 37,7 MB/s
$ ls -l mon_fichier41
-rw-r--r-- 1 root root 6903920 26 mai 11:21 mon_fichier41
$
La commande iconv permet de transformer l'encodage d'un flux de données, typiquement de l'encodage UTF8 vers ISO8859-15 et inversement.
Syntaxe
iconv options [fichiers_a_traiter]
Principales options :
-f encodage_entree : Encodage du fichier d'entrée
-t encodage_sortie : Encodage du fichier de sortie
Exemples
Conversion du fichier fic1 (UTF-8) vers fic2 (ISO8859-15)
$ cat fic1
systèmes
$ od -c fic1
0000000 s y s t 303 250 m e s \n
0000012
$ file fic1
fic1: UTF-8 Unicode text
$ iconv -f UTF8 -t ISO885915 fic1 > fic2
$ cat fic2
syst▒mes
$ od -c fic2
0000000 s y s t 350 m e s \n
0000011
$ file fic2
fic2: ISO-8859 text
$
Afficher la liste complète de tous les jeux des codes de caractères connus.
$ iconv -l
La liste suivante contient tous les jeux des codes de caractères connus. Ceci
ne signifie pas nécessairement que toutes les combinaisons de ces noms peuvent
être utilisées dans les paramètres « FROM » et « TO » des commandes. Un jeu de codes de
caractères peut être affiché avec différents noms (aliases).
437, 500, 500V1, 850, 851, 852, 855, 856, 857, 860, 861, 862, 863, 864, 865,
866, 866NAV, 869, 874, 904, 1026, 1046, 1047, 8859_1, 8859_2, 8859_3, 8859_4,
8859_5, 8859_6, 8859_7, 8859_8, 8859_9, 10646-1:1993, 10646-1:1993/UCS4,
ANSI_X3.4-1968, ANSI_X3.4-1986, ANSI_X3.4, ANSI_X3.110-1983, ANSI_X3.110,
ARABIC, ARABIC7, ARMSCII-8, ASCII, ASMO-708, ASMO_449, BALTIC, BIG-5,
BIG-FIVE, BIG5-HKSCS, BIG5, BIG5HKSCS, BIGFIVE, BRF, BS_4730, CA, CN-BIG5,
CN-GB, CN, CP-AR, CP-GR, CP-HU, CP037, CP038, CP273, CP274, CP275, CP278,
CP280, CP281, CP282, CP284, CP285, CP290, CP297, CP367, CP420, CP423, CP424,
CP437, CP500, CP737, CP775, CP803, CP813, CP819, CP850, CP851, CP852, CP855,
CP856, CP857, CP860, CP861, CP862, CP863, CP864, CP865, CP866, CP866NAV,
CP868, CP869, CP870, CP871, CP874, CP875, CP880, CP891, CP901, CP902, CP903,
CP904, CP905, CP912, CP915, CP916, CP918, CP920, CP921, CP922, CP930, CP932,
CP933, CP935, CP936, CP937, CP939, CP949, CP950, CP1004, CP1008, CP1025,
CP1026, CP1046, CP1047, CP1070, CP1079, CP1081, CP1084, CP1089, CP1097,
CP1112, CP1122, CP1123, CP1124, CP1125, CP1129, CP1130, CP1132, CP1133,
CP1137, CP1140, CP1141, CP1142, CP1143, CP1144, CP1145, CP1146, CP1147,
CP1148, CP1149, CP1153, CP1154, CP1155, CP1156, CP1157, CP1158, CP1160,
CP1161, CP1162, CP1163, CP1164, CP1166, CP1167, CP1250, CP1251, CP1252,
CP1253, CP1254, CP1255, CP1256, CP1257, CP1258, CP1282, CP1361, CP1364,
CP1371, CP1388, CP1390, CP1399, CP4517, CP4899, CP4909, CP4971, CP5347,
CP9030, CP9066, CP9448, CP10007, CP12712, CP16804, CPIBM861, CSA7-1, CSA7-2,
CSASCII, CSA_T500-1983, CSA_T500, CSA_Z243.4-1985-1, CSA_Z243.4-1985-2,
CSA_Z243.419851, CSA_Z243.419852, CSDECMCS, CSEBCDICATDE, CSEBCDICATDEA,
CSEBCDICCAFR, CSEBCDICDKNO, CSEBCDICDKNOA, CSEBCDICES, CSEBCDICESA,
CSEBCDICESS, CSEBCDICFISE, CSEBCDICFISEA, CSEBCDICFR, CSEBCDICIT, CSEBCDICPT,
CSEBCDICUK, CSEBCDICUS, CSEUCKR, CSEUCPKDFMTJAPANESE, CSGB2312, CSHPROMAN8,
CSIBM037, CSIBM038, CSIBM273, CSIBM274, CSIBM275, CSIBM277, CSIBM278,
CSIBM280, CSIBM281, CSIBM284, CSIBM285, CSIBM290, CSIBM297, CSIBM420,
CSIBM423, CSIBM424, CSIBM500, CSIBM803, CSIBM851, CSIBM855, CSIBM856,
CSIBM857, CSIBM860, CSIBM863, CSIBM864, CSIBM865, CSIBM866, CSIBM868,
CSIBM869, CSIBM870, CSIBM871, CSIBM880, CSIBM891, CSIBM901, CSIBM902,
CSIBM903, CSIBM904, CSIBM905, CSIBM918, CSIBM921, CSIBM922, CSIBM930,
CSIBM932, CSIBM933, CSIBM935, CSIBM937, CSIBM939, CSIBM943, CSIBM1008,
CSIBM1025, CSIBM1026, CSIBM1097, CSIBM1112, CSIBM1122, CSIBM1123, CSIBM1124,
CSIBM1129, CSIBM1130, CSIBM1132, CSIBM1133, CSIBM1137, CSIBM1140, CSIBM1141,
CSIBM1142, CSIBM1143, CSIBM1144, CSIBM1145, CSIBM1146, CSIBM1147, CSIBM1148,
CSIBM1149, CSIBM1153, CSIBM1154, CSIBM1155, CSIBM1156, CSIBM1157, CSIBM1158,
CSIBM1160, CSIBM1161, CSIBM1163, CSIBM1164, CSIBM1166, CSIBM1167, CSIBM1364,
CSIBM1371, CSIBM1388, CSIBM1390, CSIBM1399, CSIBM4517, CSIBM4899, CSIBM4909,
CSIBM4971, CSIBM5347, CSIBM9030, CSIBM9066, CSIBM9448, CSIBM12712,
CSIBM16804, CSIBM11621162, CSISO4UNITEDKINGDOM, CSISO10SWEDISH,
CSISO11SWEDISHFORNAMES, CSISO14JISC6220RO, CSISO15ITALIAN, CSISO16PORTUGESE,
CSISO17SPANISH, CSISO18GREEK7OLD, CSISO19LATINGREEK, CSISO21GERMAN,
CSISO25FRENCH, CSISO27LATINGREEK1, CSISO49INIS, CSISO50INIS8,
CSISO51INISCYRILLIC, CSISO58GB1988, CSISO60DANISHNORWEGIAN,
CSISO60NORWEGIAN1, CSISO61NORWEGIAN2, CSISO69FRENCH, CSISO84PORTUGUESE2,
CSISO85SPANISH2, CSISO86HUNGARIAN, CSISO88GREEK7, CSISO89ASMO449, CSISO90,
CSISO92JISC62991984B, CSISO99NAPLPS, CSISO103T618BIT, CSISO111ECMACYRILLIC,
CSISO121CANADIAN1, CSISO122CANADIAN2, CSISO139CSN369103, CSISO141JUSIB1002,
CSISO143IECP271, CSISO150, CSISO150GREEKCCITT, CSISO151CUBA,
CSISO153GOST1976874, CSISO646DANISH, CSISO2022CN, CSISO2022JP, CSISO2022JP2,
CSISO2022KR, CSISO2033, CSISO5427CYRILLIC, CSISO5427CYRILLIC1981,
CSISO5428GREEK, CSISO10367BOX, CSISOLATIN1, CSISOLATIN2, CSISOLATIN3,
CSISOLATIN4, CSISOLATIN5, CSISOLATIN6, CSISOLATINARABIC, CSISOLATINCYRILLIC,
CSISOLATINGREEK, CSISOLATINHEBREW, CSKOI8R, CSKSC5636, CSMACINTOSH,
CSNATSDANO, CSNATSSEFI, CSN_369103, CSPC8CODEPAGE437, CSPC775BALTIC,
CSPC850MULTILINGUAL, CSPC862LATINHEBREW, CSPCP852, CSSHIFTJIS, CSUCS4,
CSUNICODE, CSWINDOWS31J, CUBA, CWI-2, CWI, CYRILLIC, DE, DEC-MCS, DEC,
DECMCS, DIN_66003, DK, DS2089, DS_2089, E13B, EBCDIC-AT-DE-A, EBCDIC-AT-DE,
EBCDIC-BE, EBCDIC-BR, EBCDIC-CA-FR, EBCDIC-CP-AR1, EBCDIC-CP-AR2,
EBCDIC-CP-BE, EBCDIC-CP-CA, EBCDIC-CP-CH, EBCDIC-CP-DK, EBCDIC-CP-ES,
EBCDIC-CP-FI, EBCDIC-CP-FR, EBCDIC-CP-GB, EBCDIC-CP-GR, EBCDIC-CP-HE,
EBCDIC-CP-IS, EBCDIC-CP-IT, EBCDIC-CP-NL, EBCDIC-CP-NO, EBCDIC-CP-ROECE,
EBCDIC-CP-SE, EBCDIC-CP-TR, EBCDIC-CP-US, EBCDIC-CP-WT, EBCDIC-CP-YU,
EBCDIC-CYRILLIC, EBCDIC-DK-NO-A, EBCDIC-DK-NO, EBCDIC-ES-A, EBCDIC-ES-S,
EBCDIC-ES, EBCDIC-FI-SE-A, EBCDIC-FI-SE, EBCDIC-FR, EBCDIC-GREEK, EBCDIC-INT,
EBCDIC-INT1, EBCDIC-IS-FRISS, EBCDIC-IT, EBCDIC-JP-E, EBCDIC-JP-KANA,
EBCDIC-PT, EBCDIC-UK, EBCDIC-US, EBCDICATDE, EBCDICATDEA, EBCDICCAFR,
EBCDICDKNO, EBCDICDKNOA, EBCDICES, EBCDICESA, EBCDICESS, EBCDICFISE,
EBCDICFISEA, EBCDICFR, EBCDICISFRISS, EBCDICIT, EBCDICPT, EBCDICUK, EBCDICUS,
ECMA-114, ECMA-118, ECMA-128, ECMA-CYRILLIC, ECMACYRILLIC, ELOT_928, ES, ES2,
EUC-CN, EUC-JISX0213, EUC-JP-MS, EUC-JP, EUC-KR, EUC-TW, EUCCN, EUCJP-MS,
EUCJP-OPEN, EUCJP-WIN, EUCJP, EUCKR, EUCTW, FI, FR, GB, GB2312, GB13000,
GB18030, GBK, GB_1988-80, GB_198880, GEORGIAN-ACADEMY, GEORGIAN-PS,
GOST_19768-74, GOST_19768, GOST_1976874, GREEK-CCITT, GREEK, GREEK7-OLD,
GREEK7, GREEK7OLD, GREEK8, GREEKCCITT, HEBREW, HP-GREEK8, HP-ROMAN8,
HP-ROMAN9, HP-THAI8, HP-TURKISH8, HPGREEK8, HPROMAN8, HPROMAN9, HPTHAI8,
HPTURKISH8, HU, IBM-803, IBM-856, IBM-901, IBM-902, IBM-921, IBM-922,
IBM-930, IBM-932, IBM-933, IBM-935, IBM-937, IBM-939, IBM-943, IBM-1008,
IBM-1025, IBM-1046, IBM-1047, IBM-1097, IBM-1112, IBM-1122, IBM-1123,
IBM-1124, IBM-1129, IBM-1130, IBM-1132, IBM-1133, IBM-1137, IBM-1140,
IBM-1141, IBM-1142, IBM-1143, IBM-1144, IBM-1145, IBM-1146, IBM-1147,
IBM-1148, IBM-1149, IBM-1153, IBM-1154, IBM-1155, IBM-1156, IBM-1157,
IBM-1158, IBM-1160, IBM-1161, IBM-1162, IBM-1163, IBM-1164, IBM-1166,
IBM-1167, IBM-1364, IBM-1371, IBM-1388, IBM-1390, IBM-1399, IBM-4517,
IBM-4899, IBM-4909, IBM-4971, IBM-5347, IBM-9030, IBM-9066, IBM-9448,
IBM-12712, IBM-16804, IBM037, IBM038, IBM256, IBM273, IBM274, IBM275, IBM277,
IBM278, IBM280, IBM281, IBM284, IBM285, IBM290, IBM297, IBM367, IBM420,
IBM423, IBM424, IBM437, IBM500, IBM775, IBM803, IBM813, IBM819, IBM848,
IBM850, IBM851, IBM852, IBM855, IBM856, IBM857, IBM860, IBM861, IBM862,
IBM863, IBM864, IBM865, IBM866, IBM866NAV, IBM868, IBM869, IBM870, IBM871,
IBM874, IBM875, IBM880, IBM891, IBM901, IBM902, IBM903, IBM904, IBM905,
IBM912, IBM915, IBM916, IBM918, IBM920, IBM921, IBM922, IBM930, IBM932,
IBM933, IBM935, IBM937, IBM939, IBM943, IBM1004, IBM1008, IBM1025, IBM1026,
IBM1046, IBM1047, IBM1089, IBM1097, IBM1112, IBM1122, IBM1123, IBM1124,
IBM1129, IBM1130, IBM1132, IBM1133, IBM1137, IBM1140, IBM1141, IBM1142,
IBM1143, IBM1144, IBM1145, IBM1146, IBM1147, IBM1148, IBM1149, IBM1153,
IBM1154, IBM1155, IBM1156, IBM1157, IBM1158, IBM1160, IBM1161, IBM1162,
IBM1163, IBM1164, IBM1166, IBM1167, IBM1364, IBM1371, IBM1388, IBM1390,
IBM1399, IBM4517, IBM4899, IBM4909, IBM4971, IBM5347, IBM9030, IBM9066,
IBM9448, IBM12712, IBM16804, IEC_P27-1, IEC_P271, INIS-8, INIS-CYRILLIC,
INIS, INIS8, INISCYRILLIC, ISIRI-3342, ISIRI3342, ISO-2022-CN-EXT,
ISO-2022-CN, ISO-2022-JP-2, ISO-2022-JP-3, ISO-2022-JP, ISO-2022-KR,
ISO-8859-1, ISO-8859-2, ISO-8859-3, ISO-8859-4, ISO-8859-5, ISO-8859-6,
ISO-8859-7, ISO-8859-8, ISO-8859-9, ISO-8859-9E, ISO-8859-10, ISO-8859-11,
ISO-8859-13, ISO-8859-14, ISO-8859-15, ISO-8859-16, ISO-10646,
ISO-10646/UCS2, ISO-10646/UCS4, ISO-10646/UTF-8, ISO-10646/UTF8, ISO-CELTIC,
ISO-IR-4, ISO-IR-6, ISO-IR-8-1, ISO-IR-9-1, ISO-IR-10, ISO-IR-11, ISO-IR-14,
ISO-IR-15, ISO-IR-16, ISO-IR-17, ISO-IR-18, ISO-IR-19, ISO-IR-21, ISO-IR-25,
ISO-IR-27, ISO-IR-37, ISO-IR-49, ISO-IR-50, ISO-IR-51, ISO-IR-54, ISO-IR-55,
ISO-IR-57, ISO-IR-60, ISO-IR-61, ISO-IR-69, ISO-IR-84, ISO-IR-85, ISO-IR-86,
ISO-IR-88, ISO-IR-89, ISO-IR-90, ISO-IR-92, ISO-IR-98, ISO-IR-99, ISO-IR-100,
ISO-IR-101, ISO-IR-103, ISO-IR-109, ISO-IR-110, ISO-IR-111, ISO-IR-121,
ISO-IR-122, ISO-IR-126, ISO-IR-127, ISO-IR-138, ISO-IR-139, ISO-IR-141,
ISO-IR-143, ISO-IR-144, ISO-IR-148, ISO-IR-150, ISO-IR-151, ISO-IR-153,
ISO-IR-155, ISO-IR-156, ISO-IR-157, ISO-IR-166, ISO-IR-179, ISO-IR-193,
ISO-IR-197, ISO-IR-199, ISO-IR-203, ISO-IR-209, ISO-IR-226, ISO/TR_11548-1,
ISO646-CA, ISO646-CA2, ISO646-CN, ISO646-CU, ISO646-DE, ISO646-DK, ISO646-ES,
ISO646-ES2, ISO646-FI, ISO646-FR, ISO646-FR1, ISO646-GB, ISO646-HU,
ISO646-IT, ISO646-JP-OCR-B, ISO646-JP, ISO646-KR, ISO646-NO, ISO646-NO2,
ISO646-PT, ISO646-PT2, ISO646-SE, ISO646-SE2, ISO646-US, ISO646-YU,
ISO2022CN, ISO2022CNEXT, ISO2022JP, ISO2022JP2, ISO2022KR, ISO6937,
ISO8859-1, ISO8859-2, ISO8859-3, ISO8859-4, ISO8859-5, ISO8859-6, ISO8859-7,
ISO8859-8, ISO8859-9, ISO8859-9E, ISO8859-10, ISO8859-11, ISO8859-13,
ISO8859-14, ISO8859-15, ISO8859-16, ISO11548-1, ISO88591, ISO88592, ISO88593,
ISO88594, ISO88595, ISO88596, ISO88597, ISO88598, ISO88599, ISO88599E,
ISO885910, ISO885911, ISO885913, ISO885914, ISO885915, ISO885916,
ISO_646.IRV:1991, ISO_2033-1983, ISO_2033, ISO_5427-EXT, ISO_5427,
ISO_5427:1981, ISO_5427EXT, ISO_5428, ISO_5428:1980, ISO_6937-2,
ISO_6937-2:1983, ISO_6937, ISO_6937:1992, ISO_8859-1, ISO_8859-1:1987,
ISO_8859-2, ISO_8859-2:1987, ISO_8859-3, ISO_8859-3:1988, ISO_8859-4,
ISO_8859-4:1988, ISO_8859-5, ISO_8859-5:1988, ISO_8859-6, ISO_8859-6:1987,
ISO_8859-7, ISO_8859-7:1987, ISO_8859-7:2003, ISO_8859-8, ISO_8859-8:1988,
ISO_8859-9, ISO_8859-9:1989, ISO_8859-9E, ISO_8859-10, ISO_8859-10:1992,
ISO_8859-14, ISO_8859-14:1998, ISO_8859-15, ISO_8859-15:1998, ISO_8859-16,
ISO_8859-16:2001, ISO_9036, ISO_10367-BOX, ISO_10367BOX, ISO_11548-1,
ISO_69372, IT, JIS_C6220-1969-RO, JIS_C6229-1984-B, JIS_C62201969RO,
JIS_C62291984B, JOHAB, JP-OCR-B, JP, JS, JUS_I.B1.002, KOI-7, KOI-8, KOI8-R,
KOI8-RU, KOI8-T, KOI8-U, KOI8, KOI8R, KOI8U, KSC5636, L1, L2, L3, L4, L5, L6,
L7, L8, L10, LATIN-9, LATIN-GREEK-1, LATIN-GREEK, LATIN1, LATIN2, LATIN3,
LATIN4, LATIN5, LATIN6, LATIN7, LATIN8, LATIN9, LATIN10, LATINGREEK,
LATINGREEK1, MAC-CENTRALEUROPE, MAC-CYRILLIC, MAC-IS, MAC-SAMI, MAC-UK, MAC,
MACCYRILLIC, MACINTOSH, MACIS, MACUK, MACUKRAINIAN, MIK, MS-ANSI, MS-ARAB,
MS-CYRL, MS-EE, MS-GREEK, MS-HEBR, MS-MAC-CYRILLIC, MS-TURK, MS932, MS936,
MSCP949, MSCP1361, MSMACCYRILLIC, MSZ_7795.3, MS_KANJI, NAPLPS, NATS-DANO,
NATS-SEFI, NATSDANO, NATSSEFI, NC_NC0010, NC_NC00-10, NC_NC00-10:81,
NF_Z_62-010, NF_Z_62-010_(1973), NF_Z_62-010_1973, NF_Z_62010,
NF_Z_62010_1973, NO, NO2, NS_4551-1, NS_4551-2, NS_45511, NS_45512,
OS2LATIN1, OSF00010001, OSF00010002, OSF00010003, OSF00010004, OSF00010005,
OSF00010006, OSF00010007, OSF00010008, OSF00010009, OSF0001000A, OSF00010020,
OSF00010100, OSF00010101, OSF00010102, OSF00010104, OSF00010105, OSF00010106,
OSF00030010, OSF0004000A, OSF0005000A, OSF05010001, OSF100201A4, OSF100201A8,
OSF100201B5, OSF100201F4, OSF100203B5, OSF1002011C, OSF1002011D, OSF1002035D,
OSF1002035E, OSF1002035F, OSF1002036B, OSF1002037B, OSF10010001, OSF10010004,
OSF10010006, OSF10020025, OSF10020111, OSF10020115, OSF10020116, OSF10020118,
OSF10020122, OSF10020129, OSF10020352, OSF10020354, OSF10020357, OSF10020359,
OSF10020360, OSF10020364, OSF10020365, OSF10020366, OSF10020367, OSF10020370,
OSF10020387, OSF10020388, OSF10020396, OSF10020402, OSF10020417, PT, PT2,
PT154, R8, R9, RK1048, ROMAN8, ROMAN9, RUSCII, SE, SE2, SEN_850200_B,
SEN_850200_C, SHIFT-JIS, SHIFT_JIS, SHIFT_JISX0213, SJIS-OPEN, SJIS-WIN,
SJIS, SS636127, STRK1048-2002, ST_SEV_358-88, T.61-8BIT, T.61, T.618BIT,
TCVN-5712, TCVN, TCVN5712-1, TCVN5712-1:1993, THAI8, TIS-620, TIS620-0,
TIS620.2529-1, TIS620.2533-0, TIS620, TS-5881, TSCII, TURKISH8, UCS-2,
UCS-2BE, UCS-2LE, UCS-4, UCS-4BE, UCS-4LE, UCS2, UCS4, UHC, UJIS, UK,
UNICODE, UNICODEBIG, UNICODELITTLE, US-ASCII, US, UTF-7, UTF-8, UTF-16,
UTF-16BE, UTF-16LE, UTF-32, UTF-32BE, UTF-32LE, UTF7, UTF8, UTF16, UTF16BE,
UTF16LE, UTF32, UTF32BE, UTF32LE, VISCII, WCHAR_T, WIN-SAMI-2, WINBALTRIM,
WINDOWS-31J, WINDOWS-874, WINDOWS-936, WINDOWS-1250, WINDOWS-1251,
WINDOWS-1252, WINDOWS-1253, WINDOWS-1254, WINDOWS-1255, WINDOWS-1256,
WINDOWS-1257, WINDOWS-1258, WINSAMI2, WS2, YU
$
Ajouter un utilisateur au système
$ sudo adduser nom_du_user
(répondre aux différentes questions posées)
Ajouter un utilisateur Samba
(après avoir créé le user au niveau du système avec la commande précédente)
$ sudo smbpasswd -a nom_du_user
(saisir le mot de passe indiqué lors de la création du user au niveau du système)
Pour afficher l'UID d'un utilisateur, saisir la commande suivante dans une console :
$ echo `grep root /etc/passwd | cut -d: -f3`
0
$
La commande grep root /etc/passwd affiche la ligne du fichier /etc/passwd contenant l'expression root
$ grep root /etc/passwd
root:x:0:0:root:/root:/bin/bash
$
La commande cut -d: -f3 permet d'extraire uniquement la 3ème valeur -f3 après découpage de la ligne en indiquant le délimiteur -d:
2 sessions GNOME ouverte sur Ubuntu. La seconde session est verrouillée et protégée par un mot de passe.
Pour la fermer, saisir la commande suivante dans une console :
$ sudo skill -KILL -u utilisateur
Pour fermer un terminal dont la connexion a été perdue (ssh par exemple)
Identifier la console à fermer :
$ w
14:32:16 up 12 days, 6:26, 2 users, load average: 0,00, 0,00, 0,00
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
toto pts/0 vm-ssh.quennec. 14:28 4:12 0.29s 0.29s -bash
toto pts/1 vm-ssh.quennec. 14:28 0.00s 0.24s 0.00s w
$
La commande w permet de visualiser les utilisateurs connectés et la commande en cours d'exécution.
Dans l'exemple ci-dessus, je suis donc actuellement connecté sur 2 terminaux pts/0 & pts/1.
On voit également que la commande w a été exécutée sur le terminal pts/1 et que le terminal pts/0 est inactif depuis 4 min et 12 sec.
Il faut donc fermer le terminal pts/0.
Identifier le processus lié au terminal à fermer :
$ ps -ef | grep toto@pts/0 | grep -v grep
toto 15236 15224 0 14:28 ? 00:00:00 sshd: toto@pts/0
$
Le terminal pts/0 est donc lié au processus 15236.
Fermer le terminal :
$ kill -s 9 15236
Pour changer l'interpréteur de commande d'un utilisateur, saisir dans une console :
Mettre par défaut l'interpréteur de commande BASH pour l'utilisateur toto
$ chsh -s /bin/bash toto
L'option -s permet d'indiquer l'interpréteur de son choix.
Si cette option n'est pas indiquée, le programme chsh s'appuie sur le fichier /etc/shells pour fournir la liste des interpréteurs à utiliser.
$ cat /etc/shells
# /etc/shells: valid login shells
/bin/csh
/bin/sh
/usr/bin/es
/usr/bin/ksh
/bin/ksh
/usr/bin/rc
/usr/bin/tcsh
/bin/tcsh
/usr/bin/esh
/bin/dash
/bin/bash
/bin/rbash
/usr/bin/screen
/bin/ksh93
/bin/zsh
/usr/bin/zsh
Le nouvel interpréteur est renseigné dans le fichier /etc/passwd pour l'utilisateur indiqué.
$ cat /etc/passwd | grep "toto"
toto:x:1020:1020:toto:/home/toto:/bin/bash
$
La commande suivante permet de se loguer en root.
Ouvrir une session avec son user puis saisir :
$ sudo su -
(Saisir son mot de passe)
Partage NFS
Pré-requis
$ sudo apt-get install nfs-common
Créer un partage
$ sudo mkdir /opt/partage_nfs
$ sudo cat >> /etc/exports <<EOF
> $_ 192.168.1.56/32(rw)
> EOF
$ sudo /etc/init.d/nfs-kernel-server restart
Ce partage sera accessible uniquement pour l'adresse IP indiquée
Afficher les partages NFS du serveur
$ showmount -e adresse_ip_du_serveur
Démarrer le serveur NFS
$ sudo /etc/init.d/nfs-kernel-server start
Redémarrer le serveur NFS
$ sudo /etc/init.d/nfs-kernel-server restart
Monter un partage NFS
à renseigner dans /etc/fstab
Monter un partage NFS via SSH
Installer sshfs
$ sudo apt-get install sshfs
Créer le répertoire servant au montage
$ sudo mkdir /mnt/ssh
Monter le partage NFS distant via SSH
$ sudo sshfs $USER@adresse_de_la_machine_distante:/nom_du_partage_nfs /mnt/ssh
Pour démonter le partage NFS
$ sudo fusermount -u /mnt/ssh
Modifier le fichier FSTAB
$ sudo gedit /etc/fstab
$ sudo nano /etc/fstab
Activer les modifications du fichier FSTAB
$ sudo mount -a
Archiver avec TAR
$ tar -cvf mon_archive.tar nom_du_fichier_a_archiver
$ tar -cvf mon_archive.tar nom_du_dossier_a_archiver
-c : Create
-v : Verbose
-f : File
Archiver des fichiers avec TAR puis les supprimer
Suppression des fichiers archivés avec l'option --remove-files
$ /bin/tar --create --file=/monDossier/monArchive.tar --remove-files /monDossier/*.jpg
Archive tous les fichiers jpg présents dans le dossier 'monDossier' puis les supprime du dossier
Désarchiver avec TAR
$ tar -xvf mon_archive.tar
-x : eXtract
-v : Verbose
-f : File
Archivage :
Création de la première sauvegarde (sauvegarde complète)
Sauvegarde du dossier /home dans le fichier /backup/archive.1.tar avec détail du contenu dans /backup/backup.list
$ tar --create --file=/backup/archive.1.tar --listed-incremental=/backup/backup.list /home
Création des sauvegardes suivantes (incrémentées uniquement avec les fichiers nouveaux et/ou modifiés)
Sauvegarde des fichiers du dossier /home dans le fichier /backup/archive.2.tar différents de ceux présents dans la liste /backup/backup.list
$ tar --create --file=/backup/archive.2.tar --listed-incremental=/backup/backup.list /home
Utilisation de la date dans le nom de l'archive générée
$ tar --create --file=/backup/archive.`date +%Y_%m_%d_%s`.tar --listed-incremental=/backup/backup.list /home
Restauration :
Restaurer la première archive complète
$ tar --extract --listed-incremental=/dev/null --file archive.1.tar
Puis restaurer les archives suivantes
$ tar --extract --listed-incremental=/dev/null --file archive.2.tar
Sur un historique de sauvegarde de 10 archives, pour restaurer l'archive 4, restaurer les archives 1, 2, 3 & 4 et ce dans le bon ordre. Ne pas restaurer directement l'archive 4, elle serait incomplète.
Compresser avec TAR & GZIP
$ tar -cvzf mon _archive.tar.gz nom_du_fichier_a_compresser
$ tar -cvzf mon _archive.tar.gz nom_du_dossier_a_compresser
-c : Create
-v : Verbose
-z : gZip
-f : File
Décompresser avec TAR & GZIP
$ tar -xvzf mon_archive.tar.gz
-x : eXtract
-v : Verbose
-z : gZip
-f : File
Pour afficher les variables d'environnements, saisir dans la console
$ printenv
Pour créer une variable d'environnement, éditer le fichier $HOME/.bashrc
Y inscrire :
export MA_VARIABLE=/mon_dossier
ou
export MA_VARIABLE=/mon_dossier/mon_fichier
Pour convertir un timestamp en format date :
$ date -d @1320822978 "+%Y-%m-%d %T"
2011-11-09 08:16:18
Pour convertir une date en timestamp :
Date au format AAAAMMJJ
$ date -d "20111109" +%s
1320793200
Voici un exemple qui permet d'exécuter une action en fonction d'un jour bien précis.
Comment recevoir automatiquement un mail tous les vendredi 13 de chaque mois :
$ if [[ `date +%u` == 5 && `date +%d` == 13 ]]; then echo "" | mail -s "Vendredi 13 : Jouer au Loto" moi@gmail.com; fi
Explications :
La fonction `date +%u` retourne le numéro du jour de la semaine. Lundi = 1... Dimanche = 7.
La fonction `date +%d` retourne le jour du mois
Sous Linux, la fonction date permet d'afficher la date du jour ou une date définie sous différentes formes.
Le script suivant (afficheDate.sh), associé au fichier contenant les différentes fonctions utilisées (fonctions.inc.sh) affiche différentes informations sur la date du jour.
$ nl afficheDate.sh
1 #!/usr/bin/bash
2 SCRIPTDIR="."
3 . $SCRIPTDIR/fonctions.inc.sh
4 echo "Date au format aaaa_mm_jj : `getDate`"
5 echo "Année : `getYear`"
6 echo "Mois : `getMonth`"
7 echo "Jour : `getDay`"
8 echo "Nous sommes le `getJourDate` `getDay` `getMoisDate` `getYear`"
9 echo "Nous sommes en semaine `getNumSemaine`"
10 echo "Nous sommes le `getNumDay` jour de l'année"
11 echo "Nous sommes le `getNumDayWeek` jour de la semaine"
12 echo "Cette année il y a `nbJourAnnee` jours"
13 echo "Il reste `nbResteJour` jour(s) avant la fin de l'année"
14 echo "Cette année il y a `nbSemAnnee` semaines"
15 echo "Il reste `nbResteSemaine` semaine(s) avant la fin de l'année"
$
$ nl fonctions.inc.sh
1 function getDate {
2 date '+%Y_%m_%d'
3 }
4 function getYear {
5 date '+%Y'
6 }
7 function getMonth {
8 date '+%m'
9 }
10 function getDay {
11 date '+%d'
12 }
13 function getJourDate {
14 date '+%A'
15 }
16 function getMoisDate {
17 date '+%B'
18 }
19 function getNumSemaine {
20 date '+%V'
21 }
22 function getNumDay {
23 typeset jour
24 jour=`date '+%j'`
25 case "$jour" in
26 1)
27 echo "1 er"
28 ;;
29 *)
30 echo "$jour ème"
31 ;;
32 esac
33 }
34 function getNumDayWeek {
35 typeset jour
36 jour=`date '+%u'`
37 case "$jour" in
38 1)
39 echo "1 er"
40 ;;
41 *)
42 echo "$jour ème"
43 ;;
44 esac
45 }
46 function nbJourAnnee {
47 typeset jour
48 typeset mois
49 typeset annee
50 jour=31
51 mois=12
52 annee=`getYear`
53 date -d $mois'/'$jour'/'$annee '+%j'
54 }
55 function nbResteJour {
56 typeset jour
57 typeset nbJourAnnee
58 typeset nbJourRestant
59 jour=`date '+%j'`
60 nbJourAnnee=`nbJourAnnee`
61 ((nbJourRestant=nbJourAnnee-jour))
62 echo $nbJourRestant
63 }
64 function nbSemAnnee {
65 typeset jour
66 typeset mois
67 typeset annee
68 jour=31
69 mois=12
70 annee=`getYear`
71 date -d $mois'/'$jour'/'$annee '+%V'
72 }
73 function nbResteSemaine {
74 typeset numSem
75 typeset nbSem
76 typeset nbSemReste
77 numSem=`getNumSemaine`
78 nbSem=`nbSemAnnee`
79 ((nbSemReste=nbSem-numSem))
80 echo $nbSemReste
81 }
$
Exécution du script :
$ ./afficheDate.sh
Date au format aaaa_mm_jj : 2011_12_19
Année : 2011
Mois : 12
Jour : 19
Nous sommes le Monday 19 December 2011
Nous sommes en semaine 51
Nous sommes le 353 ème jour de l'année
Nous sommes le 1 er jour de la semaine
Cette année il y a 365 jours
Il reste 12 jour(s) avant la fin de l'année
Cette année il y a 52 semaines
Il reste 1 semaine(s) avant la fin de l'année
$
Problème de lecture / exécution d'un fichier sous Linux créer sous Windows.
Sous Windows (DOS), les lignes de fichier se terminent par les caractères spéciaux "\r\n".
Sous UNIX, les lignes de fichier se terminent par les caractères spéciaux "\n".
Les caractères spéciaux permettant le retour chariot étant différents sous Windows (DOS) et sous Linux (UNIX), il faut penser à les convertir.
Différentes méthodes permettent de le faire.
Avec la commande sed :
$ sed -i 's/\r//g' /nom_du_fichier
Sinon, le caractère "\r" est représenté par "^M" qui s'obtient par la séquence de touches suivantes : "CTRL-V" + "CTRL-M"
$ sed -i 's/^M//' /nom_du_fichier
Avec la commande tr :
$ tr -d '\r' < /mon_fichier_source > /mon_fichier_destination
A l'inverse, convertir un fichier UNIX vers DOS
$ sed 's/$/^M/' /nom_du_fichier
Source : http://www.commentcamarche.net/faq/5978-sed-conversion-retours-chariots-...
Pour rendre un fichier exécutable
$ sudo chmod +x ./nom_du_fichier
Pour afficher la somme MD5 d'un fichier afin d'en assurer son intégrité, il suffit d'utiliser la commande md5sum.
Exemple avec le fichier "test.txt" :
$ cat test.txt
ceci est une ligne
$
Calcul de la somme MD5 du fichier "test.txt" :
$ md5sum test.txt
2f378979d16de47b9d439149be5623db test.txt
$
Modification du fichier "test.txt" :
$ echo "une nouvelle ligne" >> test.txt
$ cat test.txt
ceci est une ligne
une nouvelle ligne
$
Re-calcul de la somme MD5 du fichier "test.txt" :
$ md5sum test.txt
5c69442bc1b1084b60a81190a75c6a0e test.txt
$
Après modification du fichier, la somme MD5 du fichier n'est plus la même.
Il est également possible d'enregistrer la somme MD5 d'un fichier dans un fichier :
$ md5sum test.txt > test.md5
$ cat test.md5
5c69442bc1b1084b60a81190a75c6a0e test.txt
$
De cette manière, il est possible de controler la somme MD5 d'un fichier :
Utilisation de la commande md5sum avec l'option -c et le fichier contenant la somme MD5 en paramètre.
$ md5sum -c test.md5
test.txt: OK
$
Attention : Les 2 fichiers (celui à controler et celui contenant la somme MD5) doivent être au même endroit.
Si le fichier à controler a été altéré :
$ md5sum -c test.md5
test.txt: FAILED
md5sum: WARNING: 1 of 1 computed checksum did NOT match
$
Sous Unix, les fichiers comportant des espaces dans le nom sont très compliqués à gérer sachant que l'espace est interprété comme étant un séparateur.
Voici un exemple qui permet d'afficher la somme MD5 d'une liste de fichiers dont les noms comportent des espaces.
# ls -1
20160524 leclerc 1264.pdf
20160528 boulanger 3290.pdf
20160528 cofiroute 620.pdf
20160529 la mie caline 790.pdf
20160529 le marché aux fleurs 2050.pdf
20160601 cordonnerie leclerc 1000.pdf
20160601 leclerc 990.pdf
20160601 pharmacie 3830.pdf
Les 8 fichiers ci-dessus comportent tous des espaces dans leurs noms.
# while read f; do md5sum "$f"; done <<< $(ls)
57709e696d14838ceeff6500728d1569 20160524 leclerc 1264.pdf
9f870fb12e598c7345cb74c6db15afee 20160528 boulanger 3290.pdf
5bb71357967db84baf6ed4a5fb56c552 20160528 cofiroute 620.pdf
690471607356b9ea798d3d44d69f478d 20160529 la mie caline 790.pdf
519a250059f5d8bc93af22d2ae02512f 20160529 le marché aux fleurs 2050.pdf
a08e6094bc01a34c508761ebbdae6418 20160601 cordonnerie leclerc 1000.pdf
c8f36624113710939365dd0a4daeb30c 20160601 leclerc 990.pdf
387ce36eaa18d383bd1950ee17a4fdff 20160601 pharmacie 3830.pdf
La commande read, dans la boucle while, interprète correctement les noms de fichiers provenant de la commande ls.
Ne pas oublier les 3 chevrons vers la gauche "<<<" entre la commande ls et la boucle while
mcrypt & mdecrypt sont des programmes qui permettent de chiffrer / déchiffer des fichiers avec un mot de passe.
Le programme mcrypt créé un nouveau fichier portant l'extension .nc avec des permissions 0600
Pour l'installer :
Pour chiffrer un fichier
$ mcrypt monFichier
Enter the passphrase (maximum of 512 characters)
Please use a combination of upper and lower case letters and numbers.
Enter passphrase:
Enter passphrase:
File monFichier was encrypted.
$ ls -l monFichier*
-rw-r--r-- 1 ronan ronan 0 2011-11-05 15:24 monFichier
-rw------- 1 ronan ronan 109 2011-11-05 15:24 monFichier.nc
$
Pour chiffrer un fichier et supprimer le fichier source
$ mcrypt -u monFichier
Enter the passphrase (maximum of 512 characters)
Please use a combination of upper and lower case letters and numbers.
Enter passphrase:
Enter passphrase:
File monFichier was encrypted.
$ ls -l monFichier*
-rw------- 1 ronan ronan 109 2011-11-05 15:24 monFichier.nc
$
Pour chiffrer un fichier avec une compression gzip
$ mcrypt -z monFichier
Enter the passphrase (maximum of 512 characters)
Please use a combination of upper and lower case letters and numbers.
Enter passphrase:
Enter passphrase:
File monFichier was encrypted.
$ ls -l monFichier*
-rw-r--r-- 1 ronan ronan 0 2011-11-05 15:31 monFichier
-rw------- 1 ronan ronan 141 2011-11-05 15:31 monFichier.gz.nc
$
Lister tous les algorithmes utilisable par mcrypt
$ mcrypt --list
cast-128 (16): cbc cfb ctr ecb ncfb nofb ofb
gost (32): cbc cfb ctr ecb ncfb nofb ofb
rijndael-128 (32): cbc cfb ctr ecb ncfb nofb ofb
twofish (32): cbc cfb ctr ecb ncfb nofb ofb
arcfour (256): stream
cast-256 (32): cbc cfb ctr ecb ncfb nofb ofb
loki97 (32): cbc cfb ctr ecb ncfb nofb ofb
rijndael-192 (32): cbc cfb ctr ecb ncfb nofb ofb
saferplus (32): cbc cfb ctr ecb ncfb nofb ofb
wake (32): stream
blowfish-compat (56): cbc cfb ctr ecb ncfb nofb ofb
des (8): cbc cfb ctr ecb ncfb nofb ofb
rijndael-256 (32): cbc cfb ctr ecb ncfb nofb ofb
serpent (32): cbc cfb ctr ecb ncfb nofb ofb
xtea (16): cbc cfb ctr ecb ncfb nofb ofb
blowfish (56): cbc cfb ctr ecb ncfb nofb ofb
enigma (13): stream
rc2 (128): cbc cfb ctr ecb ncfb nofb ofb
tripledes (24): cbc cfb ctr ecb ncfb nofb ofb
$
Chiffrer un fichier en utilisant l'algorithme "DES"
$ mcrypt -a des monFichier
Enter the passphrase (maximum of 512 characters)
Please use a combination of upper and lower case letters and numbers.
Enter passphrase:
Enter passphrase:
File monFichier was encrypted.
$ ls -l monFichier*
-rw-r--r-- 1 ronan ronan 0 2011-11-05 15:31 monFichier
-rw------- 1 ronan ronan 84 2011-11-05 15:31 monFichier.nc
$
Obtenir des infos sur le fichier chiffré
$ file monFichier.nc
monFichier.nc: mcrypt 2.5 encrypted data, algorithm: des, keysize: 8 bytes, mode: cbc,
$
Déchiffrer un fichier
$ ls -l monFichier*
-rw------- 1 ronan ronan 84 2011-11-05 15:31 monFichier.nc
$ mcrypt -d monFichier.nc
Enter passphrase:
File monFichier.nc was decrypted.
$ ls -l monFichier*
-rw------- 1 ronan ronan 0 2011-11-05 15:31 monFichier
-rw------- 1 ronan ronan 84 2011-11-05 15:31 monFichier.nc
$
Ou en utilisant le programme mdecrypt
$ ls -l monFichier*
-rw------- 1 ronan ronan 84 2011-11-05 15:31 monFichier.nc
$ mdecrypt monFichier.nc
Enter passphrase:
File monFichier.nc was decrypted.
$ ls -l monFichier*
-rw------- 1 ronan ronan 0 2011-11-05 15:31 monFichier
-rw------- 1 ronan ronan 84 2011-11-05 15:31 monFichier.nc
$
Comment savoir si les fichiers présents dans le dossier "DOSSIERX" du serveur "SERVEURA" sont exactement les mêmes que ceux présents dans le dossier "DOSSIERY" du serveur "SERVEURB" ?
Grâce à la commande sha256sum et une connexion ssh correctement configurée.
Exécuter le commande suivante sur le serveur "SERVEURA".
$ find /DOSSIERX -type f -exec sha256sum {} \; | ssh SERVEURB 'cd /DOSSIERY && sha256sum --quiet -c -'
Idem, mais en excluant un dossier de la recherche (.git par exemple):
$ find /DOSSIERX -type f -not -path */.git/* -exec sha256sum {} \; | ssh SERVEURB 'cd /DOSSIERY && sha256sum --quiet -c -'
Pour connaitre la taille d'un dossier :
$ sudo du -hs /nom_du_dossier
Rechercher tous les fichiers *.jpg présents dans le répertoire ~/images (sous-répertoires inclus) et les copier dans le répertoire imagesJPG.
$ find ~/images -name '*.jpg' -print0 | xargs -I '{}' -0 cp {} ~/imagesJPG/
L'option -print0 de la commande find et -0 de la commande xargs permet de prendre en compte les fichiers comportant des espaces dans leurs noms.
La commande dd permet de créer des fichiers d'une taille bien précise.
Créer un fichier vide de 1 Mo (1024 blocs de 1Ko):
$ dd if=/dev/zero of=zzz bs=1k count=1024
1024+0 enregistrements lus
1024+0 enregistrements écrits
1048576 octets (1,0 MB) copiés, 0,0108743 s, 96,4 MB/s
$ ls -l zzz
-rw-r--r-- 1 r.quennec mkpasswd 1,0M 23 mai 10:53 zzz
$
Créer un fichier avec des données aléatoires de 1 Mo (1024 blocs de 1Ko):
$ dd if=/dev/urandom of=zzz bs=1k count=1024
1024+0 enregistrements lus
1024+0 enregistrements écrits
1048576 octets (1,0 MB) copiés, 0,239581 s, 4,4 MB/s
$ wc zzz
4074 23182 1048576 zzz
$
Lire un fichier PDF en ligne commande est possible grâce à la commande less
$ less Verne-Le_tour_du_monde_en_80_jours.InLibroVeritas.net_oeuvre18616.pdf
Jules Verne
LE TOUR DU
MONDE EN
QUATRE-VINGTS
JOURS
- Collection Romans / Nouvelles -
Retrouvez cette oeuvre et beaucoup d'autres sur
http://www.inlibroveritas.net
^L^LTable des matières
LE TOUR DU MONDE EN QUATRE-VINGTS JOURS......................1
I - DANS LEQUEL PHILEAS FOGG ET PASSEPARTOUT
S'ACCEPTENT RÉCIPROQUEMENT L'UN COMME
MAÎTRE, L'AUTRE COMME DOMESTIQUE...............................2
II - OU PASSEPARTOUT EST CONVAINCU QU'IL A ENFIN
TROUVE SON IDEAL......................................................................8
III - OU S'ENGAGE UNE CONVERSATION QUI POURRA
COUTER CHER A PHILEAS FOGG.............................................12
IV - DANS LEQUEL PHILEAS FOGG STUPEFIE
PASSEPARTOUT, SON DOMESTIQUE.......................................21
V - DANS LEQUEL UNE NOUVELLE VALEUR APPARAÎT
SUR LA PLACE DE LONDRES
...................
$
Pour modifier le propriétaire d'un fichier ou d'un dossier
$ sudo chown root /u
change le propriétaire de /u en « root ».
$ sudo chown root:staff /u
même chose en changeant également le groupe en « staff ».
$ sudo chown -hR root /u
change le propriétaire de /u et ses sous-fichiers en « root ».
Changer le propriétaire et/ou le groupe de chaque FICHIER en PROPRIÉTAIRE et/ou GROUPE. Avec l’option --reference, modifier le propriétaire et le groupe de chaque fichier en celui du FICHIER-R.
-c, --changes utiliser le mode bavard en ne signalant que les modifications --dereference affecter la cible de chaque lien symbolique (comportement par défaut) plutôt que le lien symbolique lui-même -h, --no-dereference modifier les liens symboliques au lieu des fichiers référencés (utile seulement sur les systèmes permettant de changer le propriétaire d’un lien symbolique) --from=PROPRIETAIRE_COURANT:GROUPE_COURANT changer le propriétaire et/ou le groupe de chaque fichier seulement s’il y a concordance avec le propriétaire et/ou le groupe courant spécifié. Les deux peuvent être omis, auquel cas la concordance n’est pas requise pour le paramètre non spécifié --no-preserve-root ne pas traiter « / » de manière spéciale (par défaut) --preserve-root ne pas opérer récursivement sur « / » -f, --silent, --quiet supprimer la plupart des messages d’erreur --reference=FICHIER-R utiliser le propriétaire et le groupe du FICHIER-R au lieu de valeurs explicites PROPRIÉTAIRE:GROUPE -R, --recursive modifier récursivement fichiers et répertoires -v, --verbose afficher un diagnostic pour chaque fichier traité Les options suivantes modifient la façon dont est parcourue la hiérarchie lorsque l’option -R est également spécifiée. Si plus d’une option est spécifiée, seule la dernière est prise en compte. -H si un paramètre de la ligne de commande est un lien symbolique vers un répertoire, le parcourir -L parcourir chaque lien symbolique rencontré menant à un répertoire -P ne parcourir aucun lien symbolique (par défaut) --help afficher l’aide-mémoire et quitter --version afficher le nom et la version du logiciel et quitter Le propriétaire n’est pas modifié s’il n’est pas spécifié. Le groupe reste inchangé s’il n’est pas spécifié, sauf si cela est implicitement demandé avec un « : » suivant un PROPRIÉTAIRE symbolique, auquel cas il sera modifié en ce nom de propriétaire. Le PROPRIÉTAIRE et le GROUPE peuvent être numériques ou symboliques.
Pour modifier les permissions d'un fichier ou d'un dossier
$ sudo chmod 777 ./nom_du_fichier
modifie les permissions pour le fichier
$ sudo chmod 777 ./nom_du_dossier
modifie les permissions pour le dossier
$ sudo chmod -R 777 ./nom_du_dossier
modifie les permissions pour le dossier et tous les fichiers du dossier
Les permission sont données dans l'ordre user - groupe - autre
La lecture = 4
L'écriture = 2
L'exécution = 1
Tous les droits = 7
Pour connaitre le nom du dossier courant, saisir dans une console la commande :
$ pwd
Pour se rendre dans son répertoire personnel saisir dans une console l'une des 2 commandes suivantes:
$ cd
$ cd ~
Pour retourner au dossier précédent :
$ cd -
Rechercher les dossiers modifiés dans les dernières 24 heures et lister leurs contenus :
$ find /dossier_origine/* -mtime 0 -type d -exec ls -lht {} \;
l'option -mtime permet de spécifier le nombre de période de 24 heures.
l'option -type d permet d'indiquer que la recherche s'effectue uniquement sur les dossiers.
l'option -exec ls -lht {} \; permet d'exécuter la commande ls pour chaque dossier trouvé.
Le principe est simple. La commande find recherche tous les fichiers comportant un espace puis exécute pour chaque fichier trouvé la commande rename qui remplace tous les espaces par des underscores.
$ find ./ -depth -name "* *" -exec rename 's/ /_/g' "{}" \;
Pour renommer un fichier, il suffit d'utiliser la commande mv.
Exemple :
$ mv ./foo ./bar
Cette commande va renommer le fichier foo en bar.
Voici une petite astuce bien sympa qui consiste à renommer un fichier en y ajoutant une extension quelconque.
$ mv ./foo{,.txt}
Cette commande va donc renommer le fichier foo en foo.txt
En utilisant l'option -delete
$ sudo find /mon-repertoire -name mon-document -delete
ou en utilisant l'option -exec et la fonction rm
$ sudo find /mon-repertoire -name mon-document -exec rm {} \;
la chaine de caractère "{}" est remplacée par le résultat de la recherche
ou en combinant les commandes find, xargs et rm
$ find /mon-repertoire -name '*.txt' -print0 | xargs -0 rm -f
$ find /mon-repertoire -name '*.txt' -print0 | xargs -I '{}' -0 rm -f {}
L'option -print0 de la commande find et -0 de la commande xargs permet de prendre en compte les fichiers comportant des espaces dans leurs noms.
La synchronisation de dossiers et/ou de fichiers se fait via le programme RSYNC
$ sudo rsync -av --del /source_a_sauvegarder/ /destination_de_la_sauvegarde/
-a : préserve l'intégralité des dossiers et fichiers
-v : verbose (affiche le détail à l'écran)
--del : supprime les fichiers et dossiers de destination qui ne sont plus dans source
rsync via SSH
$ rsync -a /source/ login@serveur.org:/destination/
SCP (Secure Copy Protocol) est un protocole permettant le transfert de fichiers en toute sécurité d'une machine locale vers une machine distante et inversement. Tous les transferts de fichiers sont effectués via le protocol SSH.
Transférer le fichier local file1.txt vers le répertoire courant de la machine distante 192.168.1.100
$ scp ./file1.txt user@192.168.1.100:./
Transférer le fichier file1.txt de la machine distante vers le répertoire courant de la machine locale
$ scp user@192.168.1.100:./file1.txt ./
Transférer tout le répertoire local /var/test vers le répertoire /tmp de la machine distante 192.168.1.100
$ scp -r /var/test user@192.168.1.100:/tmp/
SSH permet d'utiliser des pipelines de commandes, et d'utiliser des tubes d'entrées/sorties comme toute autre commande, a ceci prêt que la redirection se fait vers, ou depuis la machine distante.
Celà peut, entre autre, servir à transférer des fichiers:
$ ssh serveur "cat fichier_distant" > fichier_local
L'utilité d'une telle commande est discutable, la commande scp faisant exactement la même chose.
Maintenant, imaginons un fichier de plusieurs mégas, et une bande passante assez limitée:
$ ssh serveur "gzip -c fichier_distant" > fichier_local.gz
ici, le serveur compresse le fichier, la commande écrit le fichier compressé sur le client.
On peut pousser encore plus loin, si l'on ne veut pas récupérer un fichier gzipé, mais diminuer quand même l'utilisation de la bande passante:
$ ssh serveur "gzip -c fichier_distant" |gunzip > fichier_local
Pour imprimer un document via la console, il faut utiliser le commande LPR
$ lpr /mon-document
$ lpr -P nom-de-l-imprimante /mon-document
$ lpr -U $USER /mon-document
$ lpr -o mirror /mon-document
Télécharger un fichier d'internet
$ wget adresse_du_fichier_a_telecharger
$ fetch adresse_du_fichier_a_telecharger
$ wget -r -l5 -k -E "http://www.l_adresse_du_site.a_recuperer.com"
-r : récursif sur le site
-l5 : cinq niveaux de récursion au maximum
-k : convertir les destinations des liens pour une lecture locale
-E : convertir les types de fichier au format HTML (pour éviter que la lecture de sites en PHP ne foire en lecture sous Firefox).
$ sudo apt-get install httrack
Pour aspirer le site :
$ httrack --mirror http://mon-site.com
Pour mettre à jour le site aspirer (se placer dans le dossier du site):
$ httrack --update
La commande curl est très utile pour afficher, tester etc... un site internet.
On peut également utiliser la commande curl pour afficher les informations SSL des sites internet.
Par exemple, avec mon site internet https://quennec.fr
# curl -I --verbose https://quennec.fr* Trying 51.159.70.99:443...
* TCP_NODELAY set
* Connected to quennec.fr (51.159.70.99) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use h2
* Server certificate:
* subject: CN=quennec.fr
* start date: Mar 11 07:02:14 2024 GMT
* expire date: Jun 9 07:02:13 2024 GMT
* subjectAltName: host "quennec.fr" matched cert's "quennec.fr"
* issuer: C=US; O=Let's Encrypt; CN=R3
* SSL certificate verify ok.
...
<
* Connection #0 to host quennec.fr left intact
On peut voir qui a émis le certificat, ses dates de validité etc etc ...
Et sinon, la commande openssl permet de récupérer le certificat complet, voir openssl : Récupérer un certificat distant
La commande CURL peut être utilisée pour poster des données via un formulaire WEB.
Exemple avec la commande suivante:
$ curl \
--insecure \
--request POST \
--header 'Content-Type: multipart/form-data' \
'https://www.monsite.com/monformulaire' \
-F 'username=toto' \
-F 'password=pass4toto' \
-F 'date-de-naissance=11-02-82' \
-F "file=@monfichier.txt" \
--include
Détail des options:
--insecure permet d'utiliser une connexion sécurisée (https) avec un certificat auto-signé (non reconnu)
--request POST permet d'indiquer le type de la requête
--header 'Content-Type: multipart/form-data' permet d'indiquer l'en-tête de la requête
-F permet d'indiquer les valeurs pour les différents champs du formulaire
--include permet de récupérer l'en-tête de la réponse
Pour poster un fichier, il est nécessaire de préfixer le nom du fichier avec l'arobase (@)
Pour appeler un webservice SOAP avec la commande CURL, il suffit d'indiquer le bon content-type dans le header ainsi que le nom du fichier XML à envoyer.
# curl \
> --header "content-type: application/soap+xml; charset=utf-8" \
> --data @request.xml \
> http://$SERVER:$PORT/$ENDPOINT
Ne pas oublier le symbole '@' devant le nom du fichier XML pour indiquer à la commande CURL qu'il s'agit d'un fichier.
Pour utiliser un serveur proxy avec la commande curl, il suffit tout simplement de créer dans son home un fichier .curlrc
Il est possible d'y ajouter différents paramètres liés à la commande curl
$ cat .curlrc
--proxy-user "user_toto:pass_toto"
--proxy "http://proxy.mondomaine.local:3128/"
--noproxy "localhost,127.0.0.1,mondomaine.local"
Ne pas oublier de paramétrer les accès au fichier
$ chmod 0600 .curlrc
Qu'est ce qu'un sprite CSS ?
En CSS, un sprite est une image unique regroupant plusieurs images différentes.
Cela permet de réduire les requêtes http pour les images insérées dans une page html.
Les positions absolues de chaque images sont indiquées dans un fichier css.
Avec ce procédé, l'insertion d'une image dans une page html ne se fait plus avec la balise <img> mais avec une balise <div> ayant comme nom de "class" celui correspondant à l'image souhaitée et indiqué dans le fichier css.
Il existe sous Debian/Ubuntu, mais également pour Windows et OSX, une commande qui permet de générer un sprite CSS à partir d'un dossier contenant des images.
Cette commande se nomme Glue.
Pour l'installer sous Debian/Ubuntu :
$ sudo apt-get install libjpeg62 libjpeg62-dev zlib1g-dev python-dev python-pip
$ sudo pip install glue
ou
$ sudo apt-get install glue-sprite
Créer un sprite CSS tout simplement
$ glue source_dir output_dir
Par exemple :
$ glue famfamfam_flag_icons/png sprite
Le dossier famfamfam_flag_icons/png contient exactement 247 images PNG et la commande glue va donc créer un unique fichier PNG dans le dossier sprite regroupant toutes les images et un fichier css indiquant les positions de chaque image.
Il est possible de générer également la page html permettant de visualiser le résultat en ajoutant l'option --html.
$ glue famfamfam_flag_icons/png sprite --html
$ ls -1 sprite/
png.css
png.html
png.png
La commande glue génère les fichiers css, html et png en fonction du nom du dossier indiqué en source.
Par défaut, le nom des "class" commence par sprite-leNomDuDossierSource-leNomDuFichier.
$ glue famfamfam_flag_icons/png sprite --namespace=monSprite
La liste complète des options est disponible avec l'option -h.
$ glue -h
Voici un exemple de l'image globale générée à l'aide de la commande glue.
Monter une clé USB ou un disque dur externe en ligne de commande avec la commande mount.
$ sudo fdisk -l
...
Disque /dev/sdd: 4009 Mo, 4009754624 octets
23 têtes, 23 secteurs/piste, 14804 cylindres
Unités = cylindres de 529 * 512 = 270848 octets
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Identifiant de disque : 0xc3072e18
Périphérique Amorce Début Fin Blocs Id Système
/dev/sdd1 * 16 14805 3911744 b W95 FAT32
$
La syntaxe de la commande mount est la suivante :
mount -t type device dir
type correspond au système de fichiers du périphérique à monter.
device correspond au fichier de la partition à monter.
dir correspond au répertoire dans lequel sera monté le périphérique.
Pour le paramètre type, il existe différents formats pris en charge :
adfs, affs, autofs, cifs, coda, coherent, cramfs, debugfs, devpts, efs, ext, ext2, ext3, ext4, hfs, hfsplus, hpfs,iso9660, jfs, minix, msdos, ncpfs, nfs, nfs4, ntfs, proc, qnx4,ramfs, reiserfs, romfs, squashfs,smbfs, sysv, tmpfs, ubifs, udf, ufs, umsdos, usbfs, vfat, xenix, xfs,xiafs
$ sudo mkdir /mnt/ma_cle_usb
$
$ sudo mount -t vfat /dev/sdd1 /mnt/ma_cle_usb/
$
Pour vérifier la bonne exécution du montage
$ mount
...
/dev/sdd1 on /mnt/ma_cle_usb type vfat (rw)
$
Avec cette commande, on s'aperçoit que le prériphérique est monté en RW (lecture/écriture).
Pour monter le périphérique en lecture seule, il suffit d'utiliser l'option -r.
$ sudo mount -r -t vfat /dev/sdd1 /mnt/ma_cle_usb/
$ mount
...
/dev/sdd1 on /mnt/ma_cle_usb type vfat (ro)
$
Pour démonter le périphérique
$ sudo umount -f /mnt/ma_cle_usb/
$
L'option -f permet de forcer le démontage
Une erreur souvent rencontrée
Un périphérique est monté et l'erreur suivante apparait lors du démontage
$ sudo umount /mnt/ma_cle_usb/
démontage : /mnt/ma_cle_usb: périphérique occupé.
(Dans certains cas, des infos sur les processus l'utilisant
sont récupérables par lsof(8) ou fuser(1))
$
Vérifier le répertoire dans lequel on se trouve
$ pwd
/mnt/ma_cle_usb
$
La commande pwd indique que je me trouve dans le répertoire que je veux démonter.
Le démontage est donc impossible car le répertoire concerné est en cours d'utilisation.
Il suffit donc de se placer dans un autre répertoire et d'exécuter à nouveau la commande umount.
$ cd
$ sudo umount /mnt/ma_cle_usb/
$
La commande mount utilisée avec l'option -a permet d'exécuter tous les points de montage inscrits dans le fichier /etc/fstab
$ sudo mount -a
Très pratique pour vérifier toutes les modifications effectuées dans le fichier /etc/fstab
Si une partition n'a plus d'espace libre disponible, elle est montée en lecture seule.
# mount
...
/dev/sdb1 on /mnt/datas type ext4 (ro)
...
Pour pouvoir y faire le ménage, il est nécessaire de pouvoir y accéder en écriture.
Pour ce faire, la partition doit être remontée en écriture de cette manière:
# mount -o remount,rw /mnt/datas
# mount
...
/dev/sdb1 on /mnt/datas type ext4 (rw)
...
Pour créer un lien symbolique
Avant toute chose, se mettre dans le répertoire dans lequel on souhaite créer le lien :
$ ln -s /nom_du_dossier_source nom_du_lien
$ ln -s /emplacement/nom_du_fichier_source nom_du_lien
Ou en utlisant les chemins absolus :
$ ln -s /emplacement/nom_du_fichier_source /emplacement/nom_du_lien
Sous GNU/Linux, il existe une commande permettant de générer une séquence de nombre.
Il s'agit de la commande seq.
Cette commande s'utilise avec ou sans options et avec un nombre d'arguments allant de 1 à 3.
Un seul argument indique la fin de la séquence.
Deux arguments indiquent le début et la fin de la séquence.
Trois arguments indiquent le début, le pas et la fin de la séquence.
Générer une séquence simple jusqu'à 10 :
$ seq 10
1
2
3
4
5
6
7
8
9
10
Générer une séquence allant de 5 à 10 :
$ seq 5 10
5
6
7
8
9
10
Générer une séquence allant de 1 à 10 avec un pas de 2 :
$ seq 1 2 10
1
3
5
7
9
Par défaut, le séparateur est le retour chariot. L'option -s permet de modifier ce séparateur :
$ seq -s "-" 1 2 10
1-3-5-7-9
L'option -w permet d'avoir une séquence dont les nombres ont le même nombre de caractères :
$ seq -w 0 100
000
001
002
003
004
005
006
007
008
009
...
098
099
100
Parcourir une séquence avec une boucle for :
$ for i in $(seq 0 2 10); do echo $i; done
0
2
4
6
8
10
Il existe une autre méthode permettant de générer une séquence de nombres, ou de lettres :
$ echo {1..5}
1 2 3 4 5
$ echo {5..-4}
5 4 3 2 1 0 -1 -2 -3 -4
$ echo {a..z}
a b c d e f g h i j k l m n o p q r s t u v w x y z
$ echo "Nombre #"{1..7},
Nombre #1, Nombre #2, Nombre #3, Nombre #4, Nombre #5, Nombre #6, Nombre #7,
$ echo {1..5}{x..z}" +" "..."
1x + 1y + 1z + 2x + 2y + 2z + 3x + 3y + 3z + 4x + 4y + 4z + 5x + 5y + 5z + ...
$ echo {001..090}
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090
$ for j in {1..10}; do echo $j; done
1
2
3
4
5
6
7
8
9
10
Générer toutes les combinaisons possibles pour les immatriculations automobiles françaises :
$ echo {A..Z}{A..Z}"-"{001..999}"-"{A..Z}{A..Z}
Attention. Cette commande génère un peu moins de 460 millions de données.
Initialisation du tableau A :
$ TAB_A=(25 46 98 3 9 10 21 15 6)
$ echo ${TAB_A[*]}
25 46 98 3 9 10 21 15 6
Initialisation du tableau B contenant les valeurs triées du tableau A :
$ TAB_B=($(echo ${TAB_A[*]} | sed 's/ /\n/g' | sort -n))
$ echo ${TAB_B[*]}
3 6 9 10 15 21 25 46 98
L'astuce consiste à afficher les valeurs du tableau A, puis substituer les espaces entre les différentes valeurs par des retours à la ligne et enfin utiliser la commande sort pour trier les valeurs.
Sous Debian/Ubuntu, il existe une commande qui permet de transformer la console en calculatrice.
Cette commande s'appelle bc.
Pour l'installer :
$ apt-get install bc
Utilisation (en rouge les résultats affichés) :
$ bc
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
5*8
40
15+9
24
45/8
5
Sans option, la commande bc exécute les calculs sans les décimales.
Pour afficher les décimales, il suffit d'utiliser l'option -l
$ bc -l
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
5*8
40
9-5
4
6+8
14
40/5
8.00000000000000000000
45/8
5.62500000000000000000
Par défaut, l'option -l affiche 20 chiffres après la virgule.
Pour modifier cette valeur, il suffit d'utiliser la fonction scale.
$ bc -l
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
scale=5
45/8
5.62500
Il est également possible d'utiliser des variables.
Calculer la valeur de pi :
pi est égal à 4 fois l'arc tangente de 1 radian.
J'ai récemment été confronté à l'erreur "integer expression expected" lors d'un test de deux entiers dans un de mes scripts.
Après plusieurs tests, j'ai finalement compris d'où venait mon erreur.
La variable que je testais ne contenait pas que des chiffres.
Elle n'était donc pas reconnue comme un entier.
Un simple "echo" de ma variable ne faisait pas apparaître tous les caractères de celle-ci.
Pour m'en apercevoir, j'ai dû utiliser la commande "od".
Exemple :
Je vais générer volontairement une erreur au niveau du contenu de la variable à tester en y insérant un caractère spécifique.
$ a=$(echo -e "20\a")
$ echo $a
20
La commande "echo" ne fait pas apparaitre le caractère spécifique contenu dans ma variable.
Je test si ma variable est égale à 20 (par exemple).
$ test $a -eq 20
-bash: test: 20: integer expression expected
J'ai bien une erreur car effectivement ma variable ne peut pas être considérée comme un entier à cause du caractère spécifique qu'elle contient.
La preuve avec la commande "od -c" ...
$ echo -n $a | od -c
0000000 2 0 \a
... le caractère spécifique "\a" apparait bien.
En conclusion, penser à bien vérifier le contenu des variables avec la commande "od" pour voir si des caractères spécifiques ne s'y sont pas insérés.
Pour envoyer un mail via une console Ubuntu :
$ mail -s "sujet du mail" adresse@destinataire.fr
Appuyer sur Entrée, renseigner si besoin une adresse CC, appuyer à nouveau sur Entrée, saisir le texte du message, appuyer une dernière fois sur Entrée puis appuyer sur les touches ctrl+d
Si cette commande est enregistrée dans un script, et si ce script est exécuté automatiquement via une tâche Cron, il n'y a pas de demande concernant l'adresse CC et le texte du message.
Pour envoyer un mail avec une pièce jointe via une console Ubuntu :
Installer le paquet mutt :
$ sudo apt-get install mutt
Envoyer un mail via cette commande :
$ mutt -s "sujet du mail" adresse@destinataire.fr -a /nom_du_fichier
$ mutt -s "Sujet du mail" -a /mon_dossier/mon_fichier -- destinataire@domaine.com
Valider les différentes étapes puis appuyer sur y pour envoyer le mail.
Si cette commande est utilisée dans un script et exécuté automatiquement via une tâche cron, le message est envoyé sans aucune étape supplémentaire à valider
Attention, dans la commande mutt, l'ajout d'une pièce jointe se fait exclusivement en dernier paramètre sans compter l'adresse du destinataire.
Pour envoyer un mail via Telnet :
$ telnet adresse_ip_du_serveur 25
helo votre_nom
mail from:<votreadresse@votredomaine.fr>
rcpt to:<adressedestinataire@domaine.fr>
data
votre message
. (le point est très important, il indique la fin du message)
quit
Il est quand même plus agréable de recevoir un mail en HTML qu'en texte brut.
La commande mail propose l'option -a qui permet de modifier l'en-tête du message.
Comme des exemples valent mieux qu'une grande explication :
$ echo "<html><head></head><body><p>Mon premier mail en <b>HTML</b></p></body></html>" | mail -a "MIME-Version: 1.0" -a "Content-Type: text/html" -s "Message" moi@gmail.lui
C'est quand même vachement simple.
Ecrire du HTML avec la commande echo, c'est sympa, mais un peu chiant si le message est long et pleins de balises.
Qu'à cela ne tienne, on écrit le HTML dans un fichier et on envoie le contenu du fichier par mail.
$ cat testMail.html
<html>
<head>
</head>
<body>
<h1>Mon Premier Mail En HTML</h1>
<p>
Qu'est ce que c'est chouette de pouvoir écrire des mails en HTML
</p>
<P>
On peut y insérer des liens ... <br />
<a href="http://www.quennec.fr">Mon Site</a> <br />
<a href="mailto:moi@gmail.lui">Mon mail</a>
</p>
</body>
</html>
$ cat testMail.html | mail -a "MIME-Version: 1.0" -a "Content-Type: text/html" -s "Message" moi@gmail.lui
De mieux en mieux.
Bonus :
Je m'envoie très souvent par mail des données issues de requêtes SQL.
Qu'est ce que c'est moche la représentation des tableaux en texte brut.
L'option -H utilisée avec la commande mysql permet de formater le résultat en tableau HTML.
Le top du top.
$ ( echo -n "<html><head></head><body>" ; echo "select col1, col2, col3 from maTable" | mysql -H -h localhost -u user -ppass maBase ; echo "</body></html>" ) | mail -a "MIME-Version: 1.0" -a "Content-Type: text/html" -s "Le Résultat de ma requête" moi@gmail.lui
Petite explication :
On affiche, avec la commande echo, la balise <html><head> </head> et <body> sans retour à la ligne avec l'option -n.
On enchaine avec la requête SQL (echo "select ...") qu'on transmet à mysql avec un "|" et qu'on exécute avec l'option -H pour afficher le résultat au format HTML.
On enchaine avec la commande echo pour afficher la balise fermante </body> et </html>.
On regroupe toutes ces commandes entre parenthèses afin de les envoyer à la commande mail avec un "|".
On indique à la commande mail d'envoyer le contenu du mail au fromat HTML grâce aux paramètres de l'option -a.
La classe, non ?
OpenSSL est un programme utilisant les protocoles de chiffrement SSL (v2/v3) et TLS (v1).
Il est utilisé principalement pour :
Quelques liens consernant SSL
Autorités de certification:
Tests de sécurité SSL:
Générateur de configuration SSL pour apache, nginx, haproxy, aws elb:
Mozilla SSL Configuration Generator
$ openssl version
OpenSSL 0.9.8o 01 Jun 2010
$ openssl version -a
OpenSSL 0.9.8o 01 Jun 2010
built on: Mon Feb 11 21:27:58 UTC 2013
platform: debian-i386-i686/cmov
options: bn(64,32) md2(int) rc4(idx,int) des(ptr,risc1,16,long) blowfish(idx)
compiler: gcc -fPIC -DOPENSSL_PIC -DZLIB -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -DL_ENDIAN -DTERMIO -O3 -march=i686 -Wa,--noexecstack -g -Wall -DOPENSSL_BN_ASM_PART_WORDS -DOPENSSL_IA32_SSE2 -DSHA1_ASM -DMD5_ASM -DRMD160_ASM -DAES_ASM
OPENSSLDIR: "/usr/lib/ssl"
$
$ openssl help
openssl:Error: 'help' is an invalid command.
Standard commands
asn1parse ca ciphers crl crl2pkcs7
dgst dh dhparam dsa dsaparam
ec ecparam enc engine errstr
gendh gendsa genrsa nseq ocsp
passwd pkcs12 pkcs7 pkcs8 prime
rand req rsa rsautl s_client
s_server s_time sess_id smime speed
spkac verify version x509
Message Digest commands (see the `dgst' command for more details)
md2 md4 md5 rmd160 sha
sha1
Cipher commands (see the `enc' command for more details)
aes-128-cbc aes-128-ecb aes-192-cbc aes-192-ecb aes-256-cbc
aes-256-ecb base64 bf bf-cbc bf-cfb
bf-ecb bf-ofb cast cast-cbc cast5-cbc
cast5-cfb cast5-ecb cast5-ofb des des-cbc
des-cfb des-ecb des-ede des-ede-cbc des-ede-cfb
des-ede-ofb des-ede3 des-ede3-cbc des-ede3-cfb des-ede3-ofb
des-ofb des3 desx rc2 rc2-40-cbc
rc2-64-cbc rc2-cbc rc2-cfb rc2-ecb rc2-ofb
Comme indiqué, il est possible d'afficher les détails des sous-commandes dgst et enc.
$ openssl dgst -h
unknown option '-h'
options are
-c to output the digest with separating colons
-d to output debug info
-hex output as hex dump
-binary output in binary form
-sign file sign digest using private key in file
-verify file verify a signature using public key in file
-prverify file verify a signature using private key in file
-keyform arg key file format (PEM or ENGINE)
-signature file signature to verify
-binary output in binary form
-hmac key create hashed MAC with key
-engine e use engine e, possibly a hardware device.
-md5 to use the md5 message digest algorithm (default)
-md4 to use the md4 message digest algorithm
-md2 to use the md2 message digest algorithm
-sha1 to use the sha1 message digest algorithm
-sha to use the sha message digest algorithm
-sha224 to use the sha224 message digest algorithm
-sha256 to use the sha256 message digest algorithm
-sha384 to use the sha384 message digest algorithm
-sha512 to use the sha512 message digest algorithm
-mdc2 to use the mdc2 message digest algorithm
-ripemd160 to use the ripemd160 message digest algorithm
$ openssl enc -h
unknown option '-h'
options are
-in <file> input file
-out <file> output file
-pass <arg> pass phrase source
-e encrypt
-d decrypt
-a/-base64 base64 encode/decode, depending on encryption flag
-k passphrase is the next argument
-kfile passphrase is the first line of the file argument
-md the next argument is the md to use to create a key
from a passphrase. One of md2, md5, sha or sha1
-K/-iv key/iv in hex is the next argument
-[pP] print the iv/key (then exit if -P)
-bufsize <n> buffer size
-engine e use engine e, possibly a hardware device.
Cipher Types
-aes-128-cbc -aes-128-cfb -aes-128-cfb1
-aes-128-cfb8 -aes-128-ecb -aes-128-ofb
-aes-192-cbc -aes-192-cfb -aes-192-cfb1
-aes-192-cfb8 -aes-192-ecb -aes-192-ofb
-aes-256-cbc -aes-256-cfb -aes-256-cfb1
-aes-256-cfb8 -aes-256-ecb -aes-256-ofb
-aes128 -aes192 -aes256
-bf -bf-cbc -bf-cfb
-bf-ecb -bf-ofb -blowfish
-cast -cast-cbc -cast5-cbc
-cast5-cfb -cast5-ecb -cast5-ofb
-des -des-cbc -des-cfb
-des-cfb1 -des-cfb8 -des-ecb
-des-ede -des-ede-cbc -des-ede-cfb
-des-ede-ofb -des-ede3 -des-ede3-cbc
-des-ede3-cfb -des-ede3-cfb1 -des-ede3-cfb8
-des-ede3-ofb -des-ofb -des3
-desx -desx-cbc -rc2
-rc2-40-cbc -rc2-64-cbc -rc2-cbc
-rc2-cfb -rc2-ecb -rc2-ofb
-rc4 -rc4-40
L'option speed permet de tester les capacités du sytème pour encrypter des données avec les différents algorithmes de cryptage pendant une période donnée.
$ openssl speed
Doing md2 for 3s on 16 size blocks: 149573 md2's in 2.54s
Doing md2 for 3s on 64 size blocks: 82254 md2's in 2.74s
Doing md2 for 3s on 256 size blocks: 26039 md2's in 2.58s
Doing md2 for 3s on 1024 size blocks: 8149 md2's in 2.93s
Doing md2 for 3s on 8192 size blocks: 1072 md2's in 2.99s
Doing md4 for 3s on 16 size blocks: 3651107 md4's in 2.87s
Doing md4 for 3s on 64 size blocks: 3393515 md4's in 3.00s
Doing md4 for 3s on 256 size blocks: 2340602 md4's in 2.99s
Doing md4 for 3s on 1024 size blocks: 1045777 md4's in 3.00s
Doing md4 for 3s on 8192 size blocks: 167900 md4's in 2.96s
Doing md5 for 3s on 16 size blocks: 3080791 md5's in 2.99s
Doing md5 for 3s on 64 size blocks: 2599131 md5's in 3.00s
Doing md5 for 3s on 256 size blocks: 1577068 md5's in 2.87s
Doing md5 for 3s on 1024 size blocks: 666677 md5's in 2.99s
Doing md5 for 3s on 8192 size blocks: 102011 md5's in 2.99s
...
Pour l'exemple, mon système est capable d'encrypter 666 677 fichiers de 1024 octets en 3s maximum.
Il est possible d'effectuer le test sur un algorithme précis :
$ openssl speed sha256
Doing sha256 for 3s on 16 size blocks: 1626266 sha256's in 2.94s
Doing sha256 for 3s on 64 size blocks: 958515 sha256's in 3.00s
Doing sha256 for 3s on 256 size blocks: 415732 sha256's in 2.99s
Doing sha256 for 3s on 1024 size blocks: 127673 sha256's in 2.99s
Doing sha256 for 3s on 8192 size blocks: 16527 sha256's in 2.87s
OpenSSL 0.9.8o 01 Jun 2010
built on: Mon Feb 11 21:27:58 UTC 2013
options:bn(64,32) md2(int) rc4(idx,int) des(ptr,risc1,16,long) aes(partial) blowfish(idx)
compiler: gcc -fPIC -DOPENSSL_PIC -DZLIB -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -DL_ENDIAN -DTERMIO -O3 -march=i686 -Wa,--noexecstack -g -Wall -DOPENSSL_BN_ASM_PART_WORDS -DOPENSSL_IA32_SSE2 -DSHA1_ASM -DMD5_ASM -DRMD160_ASM -DAES_ASM
available timing options: TIMES TIMEB HZ=100 [sysconf value]
timing function used: times
The 'numbers' are in 1000s of bytes per second processed.
type 16 bytes 64 bytes 256 bytes 1024 bytes 8192 bytes
sha256 8850.43k 20448.32k 35594.45k 43724.80k 47173.93k
Il est possible également de tester les performances SSL d'un serveur distant :
$ openssl s_time -connect google.fr:443 -www / -new -ssl3
No CIPHER specified
Collecting connection statistics for 30 seconds
333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333
186 connections in 0.20s; 930.00 connections/user sec, bytes read 183024
186 connections in 31 real seconds, 984 bytes read per connection
Il est possible également de simuler un serveur SSL pour effectuer le test de performance :
1 - Générer un certificat pour le serveur simulé (répondre aux questions posées)
$ openssl req -x509 -nodes -days 365 -newkey rsa:4096 -keyout cert.pem -out cert.pem
2 - Démarrage du serveur simulé
$ openssl s_server -cert cert.pem -www
3 - Dans un autre terminal, tester les performances du serveur simulé
$ openssl s_time -connect localhost:4433 -www / -new -ssl3
No CIPHER specified
Collecting connection statistics for 30 seconds
333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333...
33333333333333333333333333
3301 connections in 6.07s; 543.82 connections/user sec, bytes read 8506677
3301 connections in 31 real seconds, 2577 bytes read per connection
$ echo -n "ceci est mon mot de passe" | openssl base64
Y2VjaSBlc3QgbW9uIG1vdCBkZSBwYXNzZQ==
$ echo -n 'ceci est un mot de passe' | openssl md5
7c1cc4a1a08c9352b50151dfa5d6edf3
Encodage en BASE64
Encoder le contenu d'un fichier sur la sortie standard :
$ cat fic1
systèmes
$ openssl enc -base64 -in fic1
c3lzdMOobWVzCg==
Encoder le contenu d'un fichier et écrire le résultat dans un autre fichier :
$ openssl enc -base64 -in fic1 -out fic1.enc
$ cat fic1.enc
c3lzdMOobWVzCg==
Encoder une chaine de caractères :
$ echo -n "secret" | openssl enc -base64
c2VjcmV0
Ne pas oublier d'ajouter l'option -n à la commande echo sinon un retour chariot sera ajouté à la chaine encodée.
Décoder une chaine de caractères :
$ echo "c2VjcmV0" | openssl enc -base64 -d
secret
Décoder le contenu d'un fichier sur la sortie standard :
$ openssl enc -base64 -in fic1.enc -d
systèmes
Décoder le contenu d'un fichier et écrire le résultat dans un autre fichier :
$ openssl enc -base64 -d -in fic1.enc -out fic1.dec
$ cat fic1.dec
systèmes
Chiffrer un fichier avec un algorithme de chiffrement et un mot de passe
1 - Choisir un algorithme de chiffrement :
$ openssl list-cipher-commands
Voir également la page de manuel de la commande enc.
2 - Chiffrer un fichier avec l'algorithme DES3 et écrire le contenu dans un autre fichier (génération d'un fichier binaire) :
$ openssl enc -des3 -salt -in fic1 -out fic1.des3
enter des-ede3-cbc encryption password:
Verifying - enter des-ede3-cbc encryption password:
$ cat fic1.des3
Salted__d▒j▒G(▒▒r▒d}▒i▒7▒▒▒▒M▒#
Pour le déchiffrage (indication du mot de passe avec l'option -pass) :
$ openssl enc -des3 -d -salt -in fic1.des3 -out file.txt -pass pass:aaaa
$ cat file.txt
systèmes
Chiffrage DES3 mais avec un encodage en BASE64 (pour un envoi par mail par exemple) :
$ openssl enc -des3 -a -salt -in fic1 -out fic1.des3
enter des-ede3-cbc encryption password:
Verifying - enter des-ede3-cbc encryption password:
$ cat fic1.des3
U2FsdGVkX1/Cl8Jr0Aw/3eDLegGPc7meTjWbUQZcNkw=
Pour le déchiffrage :
$ openssl enc -des3 -d -a -salt -in fic1.des3 -out file.txt
enter des-ede3-cbc decryption password:
$ cat file.txt
systèmes
Pour chiffrer un fichier en indiquant le mot de passe dans la ligne de commande (avec l'option -pass) :
$ openssl enc -des3 -salt -in fic1 -out fic1.des3 -pass pass:aaaa
Pour déchiffrer un fichier en indiquant le mot de passe dans un fichier :
$ openssl enc -des3 -salt -in fic1 -out fic1.des3 -pass file:/root/pass
Dans ce cas, seule la première ligne du fichier est utilisée comme mot de passe ou phrase de passe.
Pour afficher la clé de contrôle d'un fichier, il suffit d'utiliser la sous-commande dgst suivi de l'algorithme voulu.
$ openssl dgst -md5 /var/log/syslog
MD5(/var/log/syslog)= 16973fc98773afeea8b0c9c3be3ab677
$ openssl dgst -sha1 /var/log/syslog
SHA1(/var/log/syslog)= 3b0634f6793d5ed1a6260a585ea92d22badc2070
Il existe également une commande propre à chaque algorithme et qui retourne le même résultat :
$ md5sum /var/log/syslog
16973fc98773afeea8b0c9c3be3ab677 /var/log/syslog
$ sha1sum /var/log/syslog
3b0634f6793d5ed1a6260a585ea92d22badc2070 /var/log/syslog
Il est possible également de signer la clé de contrôle d'un fichier à l'aide d'une clé privée afin d'éviter toute modification sans permission :
Génération du fichier syslog.sha1 contenant la clé de contrôle et sécurisé par une clé privée (mykey2.pem).
Cliquez ici pour la génération des clés.
$ openssl dgst -sha1 -sign mykey2.pem -out syslog.sha1 /var/log/syslog
Il ne faut pas oublier de distribuer avec le fichier contenant la clé de contrôle (syslog.sha1) le fichier contenant la clé publique correspondant à la clé privée utilisée (pubkey.pem).
Par contre, ce qu'il ne faut surtout pas faire : distribuer sa clé privée (mykey2.pem).
Il faut la garder bien au chaud dans un endroit bien secret.
Pour la vérification de la clé de contrôle sécurisée, il suffit d'utiliser la commande suivante en y indiquant la clé publique correspondante à la clé privée utilisée lors de la génération de la clé de contrôle sécurisée.
$ openssl dgst -sha1 -verify pubkey.pem -signature syslog.sha1 /var/log/syslog
Verified OK
Pour exporter un certificat PEM au format PKCS#12 :
1 - Générer le certificat au format PEM :
$ openssl req -x509 -nodes -days 365 -subj '/C=FR/ST=Loire Atlantique/L=Ancenis/CN=www.monsite.fr/emailAddress=toto@gmail.com' -newkey rsa:1024 -keyout mycert.pem -out mycert.pem
Generating a 1024 bit RSA private key
...........++++++
............++++++
writing new private key to 'mycert.pem'
-----
2 - Exporter le certificat au format PKCS#12 :
$ openssl pkcs12 -export -out mycert.pfx -in mycert.pem -name "My Certificate"
Renseigner un phrase de passe si nécessaire.
Convertir un certificat PKCS#12 au format PEM :
$ openssl pkcs12 -in mycert.pfx -out mycert2.pem -nodes
Saisir la phrase de passe si nécessaire.
Pour protéger la clé privée à l'aide d'une phrase de passe :
$ openssl pkcs12 -in mycert.pfx -out mycert2.pem
La saisie d'une phrase de passe pour la protection de la clé privée est obligatoire.
La commande suivante affiche toutes les informations du certificat indiqué :
$ openssl x509 -text -in mycert.pem
Qui a émis le certificat ?
$ openssl x509 -noout -in mycert.pem -issuer
issuer= /C=FR/ST=Loire Atlantique/L=Ancenis/CN=www.monsite.fr/emailAddress=toto@gmail.com
Pour qui a-t-il été émis ?
$ openssl x509 -noout -in mycert.pem -subject
subject= /C=FR/ST=Loire Atlantique/L=Ancenis/CN=www.monsite.fr/emailAddress=toto@gmail.com
Quelle est sa période de validité ?
$ openssl x509 -noout -in mycert.pem -dates
notBefore=Apr 9 15:28:28 2013 GMT
notAfter=Apr 9 15:28:28 2014 GMT
Toutes les infos précédentes :
$ openssl x509 -noout -in mycert.pem -issuer -subject -dates
issuer= /C=FR/ST=Loire Atlantique/L=Ancenis/CN=www.monsite.fr/emailAddress=toto@gmail.com
subject= /C=FR/ST=Loire Atlantique/L=Ancenis/CN=www.monsite.fr/emailAddress=toto@gmail.com
notBefore=Apr 9 15:28:28 2013 GMT
notAfter=Apr 9 15:28:28 2014 GMT
Quelle est sa valeur de hachage ?
$ openssl x509 -noout -in mycert.pem -hash
bf163efd
Quelle est son empreinte MD5 ?
$ openssl x509 -noout -in mycert.pem -fingerprint
SHA1 Fingerprint=C1:CD:DD:29:D1:8D:23:63:6D:3F:71:AD:7E:29:DE:26:FF:D4:11:17
Et à partir d'un certificat d'un site internet (plus de détail openssl : Récupérer un certificat distant)
$ echo | openssl s_client -connect quennec.fr:443 2>&1 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | openssl x509 -text -noout -in -
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
04:f8:64:c9:8c:bb:f8:c9:6a:fd:3f:b9:b2:42:a0:c5:9c:ab
Signature Algorithm: sha256WithRSAEncryption
Issuer: C = US, O = Let's Encrypt, CN = R3
Validity
Not Before: Mar 11 07:02:14 2024 GMT
Not After : Jun 9 07:02:13 2024 GMT
Subject: CN = quennec.fr
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Modulus:
00:b3:d3:a3:d3:f3:2c:f8:75:d0:71:5f:8f:8d:c4:
...
83:f0:69:50:7a:fe:ce:a5:48:64:e1:5a:41:a0:a3:
8b:25
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Subject Key Identifier:
F0:5D:1D:A5:87:7D:61:1D:AB:74:A4:DE:14:34:F4:D7:3A:52:56:F5
X509v3 Authority Key Identifier:
keyid:14:2E:B3:17:B7:58:56:CB:AE:50:09:40:E6:1F:AF:9D:8B:14:C2:C6
Authority Information Access:
OCSP - URI:http://r3.o.lencr.org
CA Issuers - URI:http://r3.i.lencr.org/
X509v3 Subject Alternative Name:
DNS:*.quennec.fr, DNS:quennec.fr
X509v3 Certificate Policies:
Policy: 2.23.140.1.2.1
CT Precertificate SCTs:
Signed Certificate Timestamp:
Version : v1 (0x0)
Log ID : 3B:53:77:75:3E:2D:B9:80:4E:8B:30:5B:06:FE:40:3B:
67:D8:4F:C3:F4:C7:BD:00:0D:2D:72:6F:E1:FA:D4:17
Timestamp : Mar 11 08:02:14.835 2024 GMT
Extensions: none
Signature : ecdsa-with-SHA256
30:46:02:21:00:C6:D5:B3:6D:A4:45:49:25:9B:47:C9:
21:20:61:57:67:E9:EB:5A:EB:3F:80:87:3E:EF:41:F6:
7C:CD:2C:46:61:02:21:00:D8:27:12:05:AF:5E:9A:0D:
91:E9:DA:C5:5A:27:27:25:1D:31:56:A3:6D:4D:26:21:
5D:E9:08:B0:5F:1E:5F:88
Signed Certificate Timestamp:
Version : v1 (0x0)
Log ID : 76:FF:88:3F:0A:B6:FB:95:51:C2:61:CC:F5:87:BA:34:
B4:A4:CD:BB:29:DC:68:42:0A:9F:E6:67:4C:5A:3A:74
Timestamp : Mar 11 08:02:14.890 2024 GMT
Extensions: none
Signature : ecdsa-with-SHA256
30:44:02:20:41:9E:16:0F:BF:95:4F:FA:23:4F:A4:06:
...
0F:CB:99:8B:E9:87
Signature Algorithm: sha256WithRSAEncryption
0c:dd:53:bc:97:e0:18:39:94:19:fa:28:7c:67:b9:35:a4:ca:
...
04:ee:d9:9
De nos jours, il est conseillé de générer des clés d'une longueur de 2048 bits pour une meilleure sécurité.
Pour un serveur Apache (configuration SSL), il est conseillé de générer des clés sans phrase de passe. Dans le cas contraire, à chaque démarrage du service Apache, la phrase de passe sera demandée.
Avec OpenSSL, la clé privée contient également les informations de la clé publique. Il n'est donc pas nécessaire de générer la clé publique séparément.
Génération d'une clé RSA
Générer une clé simple :
$ openssl genrsa
Générer une clé de 2048 bits et la sauvegarder dans un fichier :
$ openssl genrsa -out mykey.pem 2048
Idem mais avec un cryptage DES3 et une phrase de passe :
$ openssl genrsa -des3 -out mykey.pem 2048
Génération d'une clé publique RSA
$ openssl rsa -in mykey.pem -pubout
Génération d'une clé DSA
Les clés DSA sont utilisées pour la signature d'objets divers.
Le processus de génération se déroule en deux étapes.
Premièrement, générer les paramètres permettant la génération de la clé :
$ openssl dsaparam -out dsaparam.pem 2048
Puis, générer la clé en fonction des paramètres générés ci-dessus :
$ openssl gendsa -des3 -out privkey.pem dsaparam.pem
Une phrase de passe est demandée lors de la génération de la clé DSA.
Pour ne pas avoir de phrase de passe, il suffit de supprimer le paramètre "-des3".
Supprimer la phrase de passe d'une clé privée RSA
Cette commande permet de générer une nouvelle clé privée (newkey.pem) à partir de celle protégée par une phrase de passe (mykey.pem).
$ openssl rsa -in mykey.pem -out newkey.pem
Supprimer la phrase de passe d'un certificat
Pour l'exemple, nous allons créer un certificat crypté (mycert.pem).
Ce fichier (mycert.pem) contiendra la clé privée et le certificat public et sera protégé par une phrase de passe.
$ openssl req -x509 -days 365 -subj '/C=FR/ST=Loire Atlantique/L=Ancenis/CN=www.monsite.fr/emailAddress=toto@gmail.com' -newkey rsa:2048-keyout mycert.pem -out mycert.pem
Le décryptage du certificat se déroule en deux étapes :
Génération de la clé privée à partir du certificat crypté (mycert.pem) vers le nouveau certificat (newcert.pem) :
$ openssl rsa -in mycert.pem -out newcert.pem
Ajout du certificat public dans le nouveau certificat (newcert.pem) :
$ openssl x509 -in mycert.pem >>newcert.pem
Générer une chaine aléatoire de 128 octets encodée en BASE64 :
$ openssl rand -base64 128
2/X1yDvXHdAsDYPBmToCNYFI9Vjhtt4ynVMFCcMfV0jJm+EytH22MEyMs7XV4rbB
6CdddwCD0T3sYu7hCF+Q5Dy72S3LKhZL5cbB8gaf2l+Guv/GCU/oiYTezRwLsAaN
82Sig1bnsyJeI3q67PsLS2yUhWTXiyRxv6/69EL/i30=
Générer une chaine aléatoire de 16 octets encodée en HEX :
$ openssl rand -hex 16
e114c246088060ef2af0b4f4f518b875
Générer un fichier binaire de 1024 octets :
$ openssl rand -out random-data.bin 1024
$ ls -l random-data.bin
-rw-r--r-- 1 root root 1024 Apr 11 18:21 random-data.bin
Générer une chaine aléatoire de 64 octets en utilisant le fichier spécial /dev/urandom et encodée avec la commande openssl en BASE64 :
$ head -c 64 /dev/urandom | openssl enc -base64
3wZ9RXe5bwCKzfEUElHOEJNb97SNN7QfKetKdSfAXvNhaiyCwWBWBEJupPAM2K/Q
6zx09thfwss2ffCGvencfg==
Un petit enchainement de commandes permettant de générer des mots de passe aléatoires :
$ echo $(head -c 32 /dev/urandom | strings -1) | sed 's/[[:space:]]//g'
18EC2Wl1-W
Générer un fichier d'une taille aléatoire comprise entre 0 et 50 Mo à l'aide de la fonction interne $RANDOM (50 Mo = 1024*1024*50):
$ openssl rand -out random-data.txt $(($RANDOM * 1024 * 1024 * 50 / 32767))
La fonction interne $RANDOM génère un nombre aléatoire compris entre 0 et 32767.
Générer un fichier texte de 10Mo
$ openssl rand -hex $((1024*1024*5)) > 10mbFile
1 byte étant égal à 2 caractères hexadécimal, il faut donc penser à diviser par 2 la taille du fichier désiré.
Crypter simplement un mot de passe :
$ openssl passwd MyPasswd
hMTFVzaMHJcaA
Le mot de passe à crypter ne peut excéder 8 caractères.
Ajouter un "salt" au mot de passe à crypter (mot de passe salé ;o) :
$ openssl passwd -salt 12 MyPasswd
12q97u.MW0POc
Dans ce cas précis, le "salt" ne doit pas excéder 2 caractères.
Crypter un mot de passe avec l'algorithme MD5 :
$ openssl passwd -1 MyPasswd
$1$339eK0sF$MCPIqzRKLIWsKG1kXnQiw1
Pas de limitation au niveau de la longueur du mot de passe.
Idem mais en ajoutant un "salt" :
$ openssl passwd -1 -salt 12345678 MyPasswd
$1$12345678$I3fjXxePlXzjbz7gjOzwW0
Dans ce cas, le "salt" ne doit pas excéder 8 caractères.
Idem, mais avec un "salt" généré aléatoirement :
$ openssl passwd -1 -salt $(openssl rand -base64 8) MyPasswd
$1$nSQ9OINA$1a2pvpNHjYo41N0n6FqbQ.
Par défaut, OpenSSL utilise le fichier de configuration "/etc/ssl/openssl.cnf" pour la génération des certificats.
Pour utiliser un fichier de configuration personnalisé, il suffit d'ajouter l'argument "-config {fichier_de_configuration_personnalisé}" à la commande openssl.
Avant de pouvoir générer un certificat, il faut obligatoirement générer une clé RSA ou DSA.
Tout est expliqué ici.
Dans les exemples suivants, la clé privée "mykey.pem" sera utilisée pour la génération des certificats.
Pour générer ses propres certificats, sans passer par une autorité de certification externe :
$ openssl req -new -x509 -key mykey.pem -out ca.crt -days 1095
On indique pour le paramètre "-out" le nom de l'autorité de certification à générer puis la durée de validité en jour avec le paramètre "-days"
Cette autorité de certification permettra de signer les futures demandes de certificats auto-signés.
Cette génération est à faire une seule fois.
Le Common Name à indiquer ne doit correspondre à aucun nom de domaine ayant besoin d'un certificat.
Cette autorité de certification peut-être mis à disposition du public afin d'être intégré dans les différents navigateurs comme étant une autorité de certification reconnue.
Une demande de certificat peut être utilisée sur un site comme http://www.cacert.org/ afin d'obtenir un certificat reconnu par une autorité de certification ou afin d'être signé par le certificat ca.crt généré ci-dessus.
$ openssl req -new -key mykey.pem -out mondomaine.csr
La demande "cert.csr" peut ensuite être transmise à l'autorité de certification qui fournira par la suite le certificat résultant.
Le Common Name à indiquer doit correspondre au nom de domaine pour lequel vous souhaitez un certificat.
A l'aide du certificat de certification généré au tout début (ca.crt), nous allons générer le certificat correspondant à la demande (mondomain.csr) générée ci-dessus.
$ openssl x509 -req -in mondomaine.csr -out mondomaine.pem -CA ca.crt -CAkey mykey.pem -CAcreateserial -CAserial ca.srl -days 90
L'option -CAcreateserial est à utiliser seulement la première fois.
Ceci va générer un identifiant (ca.srl).
Lors des prochaines certification (pour renouvellement ou pour d'autres domaines) l'identifiant, contenu dans le fichier ca.srl, sera incrémenté à l'aide de l'option -CAserial ca.srl
Avec Apache, il est possible d'utiliser des fichiers d'authentification pour protéger des répertoires web.
Pour générer ces fichiers d'authentification, il est nécessaire d'utiliser la commande htdigest.
La commande htdigest inscrit les données d'authentification obligatoirement dans un fichier.
Pour afficher ces mêmes informations mais uniquement sur la sortie standard (pour x raisons) il est nécessaire d'utiliser la commande openssl.
Voici un script qui permet de saisir les informations d'authentification et affiche le résultat sur la sortie standard :
$ cat htdigest.sh
#!/bin/bash
echo "Creation d'une authentification Apache"
echo "-----------------------------------------------"
read -p "Votre nom : " NAME
read -p "Apache AuthName: " AUTHNAME
read -s -p "Votre mot de passe : " PASS; echo
printf "%s:%s:%s\n" \
"$NAME" \
"$AUTHNAME" \
$(printf "${NAME}:${AUTHNAME}:${PASS}" | openssl dgst -md5)
exit 0
Exécution du script :
$ ./htdigest.sh
Creation d'une authentification Apache
-----------------------------------------------
Votre nom : toto
Apache AuthName: monSite
Votre mot de passe :
toto:monSite:ffdcd4a53fb7dd716ec2d017e93bc563
OpenSSL possède une sous-commande qui permet de tester si le nombre passé en paramètre est un nombre premier.
$ openssl prime 2
2 is prime
$ openssl prime 3
3 is prime
$ openssl prime 4
4 is not prime
$ openssl prime 11
B is prime
Le résultat est retourné sous forme hexadécimale.
En ajoutant l'option "-hex", il est possible de tester une chaine hexadécimale :
$ openssl prime 449
1C1 is prime
La représentation hexadécimale du nombre 449 est donc 1C1
$ openssl prime -hex 1C1
1C1 is prime
En prime, un petit enchainement de commandes permettant d'obtenir la liste des 168 nombres premiers inférieurs à 1000.
$ for i in $(seq 0 1000); do \
result=$(openssl prime $i) \
echo $result | grep -q "is prime$" \
if [[ $? -eq 0 ]]; then \
echo $i \
fi
done | column -x
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53
59 61 67 71 73 79 83 89 97 101 103 107 109 113 127 131
137 139 149 151 157 163 167 173 179 181 191 193 197 199 211 223
227 229 233 239 241 251 257 263 269 271 277 281 283 293 307 311
313 317 331 337 347 349 353 359 367 373 379 383 389 397 401 409
419 421 431 433 439 443 449 457 461 463 467 479 487 491 499 503
509 521 523 541 547 557 563 569 571 577 587 593 599 601 607 613
617 619 631 641 643 647 653 659 661 673 677 683 691 701 709 719
727 733 739 743 751 757 761 769 773 787 797 809 811 821 823 827
829 839 853 857 859 863 877 881 883 887 907 911 919 929 937 941
947 953 967 971 977 983 991 997
Le script suivant permet de récupérer le contenu du certificat du site indiqué en paramètre (le port est facultatif, par défaut le port 443 est utilisé).
$ cat getCertificates.sh
#!/bin/sh
HOST=$1
PORT=${2:-443}
echo | \
openssl s_client -connect ${HOST}:${PORT} 2>&1 | \
sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p'
exit 0
$
On l'exécute en lui indiquant en paramètre le nom du site et le port (facultatif).
$ ./getCertificates.sh youtube.fr 443
-----BEGIN CERTIFICATE-----
MIIF/DCCBWWgAwIBAgIKKZeNqAABAACBuDANBgkqhkiG9w0BAQUFADBGMQswCQYD
VQQGEwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzEiMCAGA1UEAxMZR29vZ2xlIElu
...
Xl7/nc7F5HgE0c+bGsAYuCoYBsDNYs8/AUTnSTeih8U9mSRRDFb9NxMkQqUWPSXO
sh4FktaXQJBJRi4IAfuUDk28c9A0Bv1ygO3FqiSu6QJ3axESCoGmF26XqDwvJtFq
-----END CERTIFICATE-----
et le certificat s'affiche à l'écran.
Voir également CURL: Afficher les informations SSL d'un domaine
Voir également openssl : Extraire les informations d'un certificat
Voici une commande permettant de générer, en une seule fois, une paire de clé (publique/privée) et une demande de certificat CSR afin d'obtenir, auprès de cacert.org par exemple, un certificat X509 associant votre clé publique générée et le nom de domaine que vous souhaitez protéger avec TLS.
$ openssl req -nodes -newkey rsa:2048 -sha256 -keyout ma_cle.key -out ma_demande.csr
Avec cette commande, nous allons créer une clé RSA de 2048 bits.
Les autres arguments de la ligne de commandes indiquent que la clé privée sera stockée dans le fichier ma_cle.key et la demande CSR sera stockée dans le fichier ma_demande.csr.
Une série de questions vous est posée.
Les deux questions les plus importantes sont celles correspondantes au common name et à l'adresse mail de contact.
Ne renseignez surtout pas de mot de passe sinon il vous sera demandé à chaque démarrage du serveur web.
Un peu contraignant lors de tâches de maintenance automatisées.
Pour vérifier la demande CSR:
$ openssl req -text -noout -verify -in ma_demande.csr
Reste à transmettre à l'autorité de certification (cacert.org par exemple - certificat gratuit) la demande CSR.
Il est possible d'utiliser la commande openssl pour se connecter à un serveur STMP en utilisant la sécurité TLS,
Dans l'exemple suivant, l'option -CAfile /etc/ssl/certs/ca-certificates.crt permet d'indiquer l'autorité de certification dans le cas d'un certificat auto signé.
# openssl s_client -starttls smtp -crlf -CAfile /etc/ssl/certs/ca-certificates.crt -connect smtp.server.fr:25
CONNECTED(00000003)
depth=0 CN = localhost.localdomain
verify return:1
---
Certificate chain
0 s:/CN=localhost.localdomain
i:/CN=localhost.localdomain
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIBtzCCASACCQCupdgFIYzFVDANBgkqhkiG9w0BAQUFADAgMR4w
b2NhbGhvaW4wHhcNMTEwNDI2MTkxMDM1WhcNMjEwNDIzMTkx
MDM1WjAgMR4wHAYDVQQDExVsb2NhbGhvc3QubG9jYWxkb21ha
hvcNAQEBBQADgY0AMIGJZS3OcCHjbQNa++F/J4WGFk6r7ICl9Ls0
ybT+1CzbFG1xE71NeRhbHkLGigZa5422afsqq/b3LBIpMX17B/gtuo+
QKRckuo+20BUqHFye7ZAVXSsw+bqmm9D0vB4uw9IwyE75jEAqU1
QX7RAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAe1iHUXoGSTj3Fv3
2Yg1EFtNm/RSYxdHV8jY6W6CtwNatN+EQqmWlfhtOSCWgXriUjX5
E4uEocf6x/vDrVkpU11u+0xDUYshmrLyk2nmX6wbopwQttAE9PLw
ahQBiuj+sz38OW8=
-----END CERTIFICATE-----
subject=/CN=localhost.localdomain
issuer=/CN=localhost.localdomain
---
No client certificate CA names sent
---
SSL handshake has read 1021 bytes and written 456 bytes
---
New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES256-GCM-SHA384
Server public key is 1024 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
Protocol : TLSv1.2
Cipher : ECDHE-RSA-AES256-GCM-SHA384
Session-ID: D2A784125E749B8C74015978412B9B6E47DDA37BFB83FD4FEE8E6ED21BE79C92
Session-ID-ctx:
Master-Key: 631649B5A6A2F5272137C421AFB2F2E86CD483ED2FE8099BCDC9068A11EE7087F
Key-Arg : None
PSK identity: None
PSK identity hint: None
SRP username: None
Start Time: 1478726847
Timeout : 300 (sec)
Verify return code: 0 (ok)
---
250 DSN
mail from: one@mail.fr
250 2.1.0 Ok
rcpt to: two@mail.fr
250 2.1.5 Ok
data
354 End data with <CR><LF>.<CR><LF>
from: one@mail.fr
to: two@mail.fr
subject: send mail with TLS connection
Voluptatem veniam quasi nisi voluptatum incidunt autem. Sed provident minus ab temporibus sed. Quia blanditiis consequatur assumenda aut hic. Minima cum qui quidem dicta velit quod voluptas. Dolorem aliquam animi consequatur.
Minima alias sint libero et. Et et in ratione similique iusto aut consectetur. Sed voluptatibus modi fuga ut quibusdam ut consectetur voluptas.
.
250 2.0.0 Ok: queued as 145A53700157
quit
221 2.0.0 Bye
closed
Très utile pour tester un serveur STMP
Avant toute chose, ne pas monter le cd-rom
Créer une image ISO avec la commande dd :
$ dd if=/dev/cdrom of=/tmp/monImage.iso
Créer une image ISO avec la commande cat :
$ cat /dev/cdrom > /tmp/monImage.iso
Pour vérifier le contenu de l'image créée :
$ mkdir /media/iso
$ sudo mount -o loop -t iso9660 /tmp/monImage.iso /media/iso/
$ sudo apt-get install dosfstools
$ sudo fdisk -l
$ mkfs.vfat /dev/sdb1
$ mkfs.vfat -F 32 -n nom_de_ma_cle_usb /dev/sdb1
Pour formater un support de stockage, celui-ci ne doit pas être monté.
$ umount /media/ma_cle_usb
Pour les autres formats :
$ apt-get install ntfs-3g ntfsprogs
$ mkntfs /dev/sde1
La commande fdisk -l ne permet pas de connaitre le type exact d'une partition.
$ fdisk -l
Disk /dev/sda: 1000.2 GB, 1000204886016 bytes
255 heads, 63 sectors/track, 121601 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disk identifier: 0x00000000
Device Boot Start End Blocks Id System
/dev/sda1 * 1 66 524288 83 Linux
Partition 1 does not end on cylinder boundary.
/dev/sda2 66 121601 976235712 8e Linux LVM
Disk /dev/sdb: 1500.3 GB, 1500299395072 bytes
255 heads, 63 sectors/track, 182401 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00026d5d
Device Boot Start End Blocks Id System
/dev/sdb1 1 182401 1465136001 83 Linux
Disk /dev/sdc: 160.0 GB, 160041885696 bytes
255 heads, 63 sectors/track, 19457 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x0008ef40
Device Boot Start End Blocks Id System
/dev/sdc1 1 19457 156288321 83 Linux
Disk /dev/sdd: 2000.4 GB, 2000396746752 bytes
255 heads, 63 sectors/track, 243201 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00101aa1
Device Boot Start End Blocks Id System
/dev/sdd1 1 243201 1953512001 83 Linux
Disk /dev/sde: 80.0 GB, 80032038912 bytes
255 heads, 63 sectors/track, 9730 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x000f2c13
Device Boot Start End Blocks Id System
/dev/sde1 1 9730 78156193+ b W95 FAT32
La commande blkid est beaucoup plus précise
$ blkid
/dev/sda1: UUID="cd34d37b-b73c-4ee4-820c-c8006043518a" SEC_TYPE="ext2" TYPE="ext3"
/dev/sda2: UUID="BVYNlC-AQG0-oDe9-I4zu-xVzp-RdV3-W1Fegr" TYPE="LVM2_member"
/dev/sdb1: UUID="a6ea6463-e289-4bbe-afba-572f876497da" TYPE="ext4"
/dev/sdc1: UUID="1a6c5464-6ae1-4205-97c5-edae82649198" SEC_TYPE="ext2" TYPE="ext3"
/dev/sdd1: UUID="8ea1a0ee-c21c-4892-bdc9-bda6186ebd98" TYPE="ext4"
/dev/sde1: UUID="4961B8D578F1B234" TYPE="ntfs"
Sur les distributions type Debian, le programme genisoimage permet de créer une image ISO d'un fichier ou d'un répertoire complet.
Pré-requis
Installer le programme genisoimage
$ apt-get install genisoimage
Exemple
$ genisoimage -r -v -J -o /tmp/image.iso /mon_repertoire
=> Création du fichier /tmp/image.iso contenant toutes les données de /mon_repertoire
Détail des options utilisées
-r : Pour permettre à tous les utilisateurs d'avoir accès aux données du disque, même si l'image est créée en tant qu'administrateur.
-v : Permet d'activer le mode verbeux.
-J : Supporte les noms longs de fichiers.
-o : Permet de spécifier le nom du fichier ISO
Sur les distributions type Debian, le programme wodim permet de graver une image ISO sur un disque.
Pré-requis
Installer le programme wodim
$ apt-get install wodim
Connaitre l'identifiant du graveur
$ wodim --devices
wodim: Overview of accessible drives (1 found) :
-------------------------------------------------------------------------
0 dev='/dev/scd0' rwrw-- : 'TSSTcorp' 'CDW/DVD TS-H492B'
-------------------------------------------------------------------------
$
Exemple
Si besoin, créer une image ISO (voir détail ici) :
$ genisoimage -r -v -J -o /tmp/image.iso /mon_repertoire
Puis graver l'image sur un disque :
$ wodim -v -speed=4 dev=/dev/scd0 -data /tmp/image.iso
Détail des options utilisées :
-v : Pour activer le mode verbeux
-speed : Pour indiquer la vitesse de gravure
dev=... : Pour indiquer le fichier identifiant du graveur
-data : Pour indiquer l'image à graver
Pour effacer rapidement un disque RW :
$ wodim -v -speed=4 -force dev=/dev/scd0 blank=fast
Pour effacer complètement un disque RW :
$ wodim -v -speed=4 -force dev=/dev/scd0 blank=all
Afficher ou sauvegarder le fichier /etc/fstab avant toute manipulation
# cat /etc/fstab
#
# /etc/fstab
# Created by anaconda on Wed Feb 8 10:04:33 2023
#
# Accessible filesystems, by reference, are maintained under '/dev/disk/'.
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info.
#
# After editing this file, run 'systemctl daemon-reload' to update systemd
# units generated from this file.
#
UUID=8db4ff33-9c01-42c5-89c9-851b58ad4599 / xfs defaults 0 0
UUID=d107b673-8b5a-4171-b30c-d03bd72b9e55 /boot xfs defaults 0 0
UUID=3AC0-FCC8 /boot/efi vfat umask=0077,shortname=winnt 0 2
UUID=fe4c581c-4b22-49d7-94a7-040600a98baa /var/log xfs defaults 0 0
UUID=33bb87c8-90e6-4107-9d70-0c4bd2f5b852 none swap defaults 0 0
UUID=5654158c-dc3e-4c69-a5f8-64c6dc7c8b08 /home xfs defaults 0 0
no-device /tmpfs tmpfs rw,seclabel,relatime 0 0
Afficher la liste des partitions ainsi que les UUIDs
# blkid
/dev/sda5: UUID="8db4ff33-9c01-42c5-89c9-851b58ad4599" BLOCK_SIZE="512" TYPE="xfs" PARTUUID="85254d0d-f5c4-6245-aae7-fd870d97413c"
/dev/sda1: UUID="3AC0-FCC8" BLOCK_SIZE="512" TYPE="vfat" PARTLABEL="EFI System Partition" PARTUUID="fc72f64e-a700-459a-ba6b-0dcaa7016747"
/dev/sda2: UUID="d107b673-8b5a-4171-b30c-d03bd72b9e55" BLOCK_SIZE="512" TYPE="xfs" PARTUUID="736002d1-0dcf-4825-8ebd-caa436560505"
/dev/sda3: UUID="33bb87c8-90e6-4107-9d70-0c4bd2f5b852" TYPE="swap" PARTUUID="6d3ef976-e9fb-425f-b7e1-7f1ff84d51e0"
/dev/sda4: UUID="fe4c581c-4b22-49d7-94a7-040600a98baa" BLOCK_SIZE="512" TYPE="xfs" PARTUUID="894d6ef9-cfa0-4945-a3db-fefdd0c94162"
/dev/sdb1: UUID="5654158c-dc3e-4c69-a5f8-64c6dc7c8b08" BLOCK_SIZE="512" TYPE="xfs" PARTUUID="3a6000f2-01"
/dev/sdc1: UUID="c822d42a-a492-4e80-8b2a-e929275b955c" BLOCK_SIZE="512" TYPE="xfs" PARTUUID="51229054-01"
/dev/sdd1: UUID="921dbe26-cc98-45bd-9445-4c87ff1f4ec0" BLOCK_SIZE="512" TYPE="xfs" PARTUUID="d8576e95-01"
Je souhaite monter la partition /dev/sdd1 dans le dossier /mnt/207, je vais copier l'UUID de la partition directement dans le fichier /etc/fstab
# echo UUID=$(blkid -o value -s UUID /dev/sdd1) >> /etc/fstab
Reste à modifier le fichier /etc/fstab pour y ajouter les informations supplémentaires
# vim /etc/fstab
#
# /etc/fstab
# Created by anaconda on Wed Feb 8 10:04:33 2023
#
# Accessible filesystems, by reference, are maintained under '/dev/disk/'.
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info.
#
# After editing this file, run 'systemctl daemon-reload' to update systemd
# units generated from this file.
#
UUID=8db4ff33-9c01-42c5-89c9-851b58ad4599 / xfs defaults 0 0
UUID=d107b673-8b5a-4171-b30c-d03bd72b9e55 /boot xfs defaults 0 0
UUID=3AC0-FCC8 /boot/efi vfat umask=0077,shortname=winnt 0 2
UUID=fe4c581c-4b22-49d7-94a7-040600a98baa /var/log xfs defaults 0 0
UUID=33bb87c8-90e6-4107-9d70-0c4bd2f5b852 none swap defaults 0 0
UUID=5654158c-dc3e-4c69-a5f8-64c6dc7c8b08 /home xfs defaults 0 0
no-device /tmpfs tmpfs rw,seclabel,relatime 0 0
UUID=921dbe26-cc98-45bd-9445-4c87ff1f4ec0 /mnt/207 xfs defaults 0 0
Reste à monter la partition
# mount -a
Pré-requis :
Avoir un client MySql installé
$ apt-get install mysql-client
Exécution d'une requête :
$ echo "select * from ma_base.ma_table where champ1 = valeur1" | mysql -u user -pmotdepasse
De cette manière, il est tout à fait possible d'exécuter une requête SQL dans un script (en bash par exemple) et d'en exploiter le résultat.
$ echo "select * from ma_base.ma_table where champ1 = valeur1" | mysql -u user -pmotdepasse > ~/mon_fichier
Il est également possible d'exécuter une requête uniquement avec le client mysql :
$ mysql ma_base -N -s -u user -p -e "select * from ma_table where 1=1"
L'option -N permet de na pas afficher le nom des champs.
L'option -s permet de ne pas afficher les délimiteurs du tableau.
L'option -e permet d'exécuter la requête suivante.
Le résultat de la requête est affiché dans la console et peut être traité par d'autres commandes.
Principe : Copier la clé contenu dans le fichier ~/.ssh/id_rsa.pub dans le fichier ~/.ssh/authorized_keys d'un host distant (ici, 192.168.0.101)
Voir également "Connexion à une machine distante (ssh, scp, sftp) sans saisir le mot de passe"
$ cd ~/.ssh
$ ls
authorized_keys id_rsa id_rsa.pub known_hosts
$ ssh-copy-id -i id_rsa.pub root@192.168.0.101
root@192.168.0.101's password:#Saisir ici le mot de passe
Now try logging into the machine, with "ssh 'root@192.168.0.101'", and check in:
~/.ssh/authorized_keys
to make sure we haven't added extra keys that you weren't expecting.
$
Sécuriser la connexion ssh par clé en associant une adresse IP/un nom de host à la clé RSA dans le fichier ~/.ssh/authorized_keys
Pour plus de sécurité il est possible d'associer une adresse IP et/ou un nom de host à une clé RSA afin d'éviter l'utilisation de cette clé sur une autre machine.
Exemple d'une clé RSA
$ cat ~/.ssh/authorized_keys
ssh-rsa iMEyIOc6TAw3+w/RBkHXbabKYgI1Y4EDEifBdcmGYMe8MshE6D27NouR1hdFyvsT
LLs+DCALHJNxkitS31HO7QlWAX9YRC1D47neCk29E1SCmG9CeWNyztgAmgI91FD6
yWtWSD3MOW27/rC+CxdXoVNSFNVJ+wKuK5QGUMlAMm+nFJi6evlVLBhGKb5LVNQ6
nszYteN5dpp/asSAU+kHyQsNJPyz1m/w8KZujYpkpV3mJh4GYvBiz2A+JWo/FRbo
3LSdFiVxt9V1rqfrYSXFcHS4jky9HSH/c9b9d1iop6lPBShlLjAf2zpQYfU5Ra7u
TQsO3D1z+dZ8NXARJ4WWHkWyIEyN67q4uKMehscDGYKy3hcyRTlJ0sw0bokNMf99
oGcmN5KKasLvUsIfMyNbSC8bcYdsOb+06QDyHHE9h2aYcoBCgvX4zhkAoDSeMsK2
Bg7h2PdV5S5bLPr/hjLgNky6u9TCbDIJOInqJZwk4/gqPOMbffuKeiN1K2lzyrfk
mX3Nnwm/ivb0IBEYLQs4GM8WyamlJtlj5K32mJfflFwnbj5+dGQhjRZ/jJ1D9PsL
U441033CepoXDIf2cV3I34aZ2V7YxEgsk4rRVEX0mGCYezBn1f4IumQ1Il9ixrEf
FktHyk6kfviQC8wOTRsABiH79KSIIqc3cp9zbOSbn+4= root@ma_machine
Exemple d'une clé RSA avec association d'une adresse IP et/ou d'un nom de host
$ cat ~/.ssh/authorized_keys
from="192.168.1.1,ma_machine.mon_domaine.com" ssh-rsa iMEyIOc6TAw3+w/RBkHXbabKYgI1Y4EDEifBdcmGYMe8MshE6D27NouR1hdFyvsT
LLs+DCALHJNxkitS31HO7QlWAX9YRC1D47neCk29E1SCmG9CeWNyztgAmgI91FD6
yWtWSD3MOW27/rC+CxdXoVNSFNVJ+wKuK5QGUMlAMm+nFJi6evlVLBhGKb5LVNQ6
nszYteN5dpp/asSAU+kHyQsNJPyz1m/w8KZujYpkpV3mJh4GYvBiz2A+JWo/FRbo
3LSdFiVxt9V1rqfrYSXFcHS4jky9HSH/c9b9d1iop6lPBShlLjAf2zpQYfU5Ra7u
TQsO3D1z+dZ8NXARJ4WWHkWyIEyN67q4uKMehscDGYKy3hcyRTlJ0sw0bokNMf99
oGcmN5KKasLvUsIfMyNbSC8bcYdsOb+06QDyHHE9h2aYcoBCgvX4zhkAoDSeMsK2
Bg7h2PdV5S5bLPr/hjLgNky6u9TCbDIJOInqJZwk4/gqPOMbffuKeiN1K2lzyrfk
mX3Nnwm/ivb0IBEYLQs4GM8WyamlJtlj5K32mJfflFwnbj5+dGQhjRZ/jJ1D9PsL
U441033CepoXDIf2cV3I34aZ2V7YxEgsk4rRVEX0mGCYezBn1f4IumQ1Il9ixrEf
FktHyk6kfviQC8wOTRsABiH79KSIIqc3cp9zbOSbn+4= root@ma_machine
Les différentes valeurs doivent être séparées par une virgule.
Le point d'interrogation permet d'indiquer un plage d'adresses IP (from="192.168.0.?").
L'astérisque permet d'indiquer tous les sous-domaines d'un domaine (from="*.mon_domaine.com").
Il est possible d'exclure en ajoutant un point d'exclamation avant (from="!autre_domaine.com").
L'outil ssh-keygen permet d'effectuer différentes manipulations sur les clés SSH.
Générer une clé SSH de type RSA:
$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/xxxx/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/xxxx/.ssh/id_rsa
Your public key has been saved in /home/xxxx/.ssh/id_rsa.pub
The key fingerprint is:
SHA256:LSPtPiOIKudk4CuQzD6MdlyJQh3RQc+xvYJTgHWPQ6E xxxx@yyyy
The key's randomart image is:
+---[RSA 3072]----+
| .*=.=. |
| o .B * |
| . .E B o |
| . . o.... |
|=. .oo.S.. |
|+= . o.o.o |
|=.=... . |
|+B+o. ..o |
|==+ ..o |
+----[SHA256]-----+
Le contenu de la clé privée (attention, celui-ci ne doit jamais être partagé)
$ cat .ssh/id_rsa
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
NhAAAAAwEAAQAAAYEApgXls7gw98Hr5Q05qB5Dlg7Agzomlm/8Q7k3yawjwgJP5+SNZ0pj
edSm8PnQZnYP00vN8KPLjTWfBo39HRJpylPq8abRs8LeIqAwKOY+7bTGEvcxACvIRd8w/U
wV6XYHVH5w9vT4gW9Lb9J1AOAcaEEcGNUwCPHiqoHa6eA2kg6e36F1ZE9DUYGw2altST7P
smWvFSPMx3eXJLpbsgaGHhzvI6cwpXkbeDILoHjws1GDcmI7X3zya46p3Zrt8cagRi3lKP
cje3xfKoLMLb3zauB8tb7pW41VP4KoplgT7r4bxd/4EkQcG9bv9AoAb7avp6f0ulBvAEw9
...
UZA+eKidhEz4we4ivxwb+GSVbCVBWkWZvEIX5+5tVPJaxi18K6GC+Zw4lOlYe4nwFtDQz8
5KI7LRQSDZrNtNiMJ/R/dOXV9l74ixlafKM1uMd5x23RmSEVzGap/tgwqam+KSeHuKN+zR
O3XW2hyx1TruD3JEcN2/hVUh5bM1q9YcSfrjd/bzFL+tQIs1t9N5TQOn/EYnLHlcsUzhLq
xWp1/EulMM4qMAAAAPcm9uYW5AUEFTUE8wMDg2AQIDBA==
-----END OPENSSH PRIVATE KEY-----
Le contenu de la clé privée (celui ci peut-être partagé avec n'importe qui)
$ cat .ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCmBeWzuDD3wevlDTmoHkOWDsCDOiaWb/xDuTfJrCPCAk/n5I1nSmN51Kbw+dBmdg/TS83wo8uNNZ8Gjf0dEmnKU+rxptGzwt4ioDAo5j7ttMYS9zEAK8hF3zD9TBXpdgdUfnD29PiBb0tv0nUA4BxoQRwY1TAI8eKqgdrp4DaSDp7foXVkT0NRgbDZqW1JPs+yZa8VI8zHd5ckuluyBoYeHO8jpzCleRt4MgugePCzUYNyYjtffPJrjqndmu3xxqBGLeUo9yN7fF8qgswtvfNq4Hy1vulbjVU/gqimWBPuvhvF3/gSRBwb1u/0CgBvtq+np/S6UG8ATD2mBS+mqB687hKB7BzY+SAWgOMfloavV7ms609c5/nQR2UwlQuHDo79Zz3uqbwVh02hRdomZC7Q9Elte9hUgdz5DZOMiC1lOh5Zj+X/POe+Rg/G8eXrbXO0IlaW4MZjqQTG8U7gLrbtkHYxljphI/eGSYnTo5Qmu77EHy0EAe/DE7HGGt0hOEU= xxxx@yyyy
Afficher le fingerprint d'une clé SSH (peu importe la clé fournie, privée ou publique, c'est toujours le fingerprint de la clé publique qui est affiché)
$ ssh-keygen -l -f .ssh/id_rsa
3072 SHA256:LSPtPiOIKudk4CuQzD6MdlyJQh3RQc+xvYJTgHWPQ6E xxxx@yyyy(RSA)
$ ssh-keygen -l -f .ssh/id_rsa.pub
3072 SHA256:LSPtPiOIKudk4CuQzD6MdlyJQh3RQc+xvYJTgHWPQ6E xxxx@yyyy(RSA)
Par défaut le fingerprint est affiché avec le hash SHA256, pour l'afficher avec le hash MD5, il suffit d'ajouter l'option -E avec le paramètre MD5
$ ssh-keygen -l -f .ssh/id_rsa.pub -E md5
3072 MD5:29:3c:60:2a:d2:49:20:82:12:c4:c5:e3:f0:95:2c:b3 xxxx@yyyy(RSA)
Afficher le fingerprint en représentation ASCII
$ ssh-keygen -l -f .ssh/id_rsa.pub -E md5 -v
3072 MD5:29:3c:60:2a:d2:49:20:82:12:c4:c5:e3:f0:95:2c:b3 xxxx@yyyy(RSA)
+---[RSA 3072]----+
|Ooo.. . |
|=+ = + |
|. = O |
| o E o . |
|o + + S |
|.. o |
| |
| |
| |
+------[MD5]------+
Recalculer la clé publique d'une clé privée
$ ssh-keygen -y -f .ssh/id_rsa
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCmBeWzuDD3wevlDTmoHkOWDsCDOiaWb/xDuTfJrCPCAk/n5I1nSmN51Kbw+dBmdg/TS83wo8uNNZ8Gjf0dEmnKU+rxptGzwt4ioDAo5j7ttMYS9zEAK8hF3zD9TBXpdgdUfnD29PiBb0tv0nUA4BxoQRwY1TAI8eKqgdrp4DaSDp7foXVkT0NRgbDZqW1JPs+yZa8VI8zHd5ckuluyBoYeHO8jpzCleRt4MgugePCzUYNyYjtffPJrjqndmu3xxqBGLeUo9yN7fF8qgswtvfNq4Hy1vulbjVU/gqimWBPuvhvF3/gSRBwb1u/0CgBvtq+np/S6UG8ATD2mBS+mqB687hKB7BzY+SAWgOMfloavV7ms609c5/nQR2UwlQuHDo79Zz3uqbwVh02hRdomZC7Q9Elte9hUgdz5DZOMiC1lOh5Zj+X/POe+Rg/G8eXrbXO0IlaW4MZjqQTG8U7gLrbtkHYxljphI/eGSYnTo5Qmu77EHy0EAe/DE7HGGt0hOEU= xxxx@yyyy
La preuve que la commande ci-dessus retourne le même résultat que la clé publique d'origine
$ ssh-keygen -y -f .ssh/id_rsa | diff .ssh/id_rsa.pub -
(le retour de la commande est vide indiquant que les contenus sont identiques)
$ ssh-keygen -H -F 192.168.1.101
$ ssh-keygen -H -F machine.domaine.com
$ ssh-keygen -R 192.168.1.101
$ ssh-keygen -R machine.domaine.com
$ ssh-keyscan -t rsa,dsa 192.168.1.100
$ ssh-keyscan -t rsa,dsa machine.domaine.com
Screen est un multiplicateur de terminal.
Cette commande permet d'avoir plusieurs consoles au sein d'une seule.
A mon avis, l'avantage principal de cette commande, est de supprimer tous les risques liés à une déconnexion de la console principale.
Effectivement, en cas de perte de la connexion à la console, toutes les commandes en cours d'exécution sont automatiquement stoppées.
Avec screen, toutes les commandes continuent à s'exécuter.
Pour l'installer et l'utiliser, il faut obligatoirement être en mode sudo :
$ sudo apt-get install screen
Utilisation de screen
$ sudo screen -S ma_console
Exécution de screen avec l'option "-S" qui permet de nommer la nouvelle console en "ma_console".
Appuyer sur les touches ctrl + a puis sur shift + ?
Pour quitter l'aide, appuyer sur espace
Taper exit
puis appuyer sur entrée
Ou appuyer sur les touches ctrl + d
Appuyer sur les touches ctrl + a puis sur d
Une fois dans la console principale, il est possible de lister les différentes consoles ouvertes avec screen sachant qu'il est tout à fait possible d'ouvrir plusieurs consoles différentes.
$ sudo screen -ls
There is a screen on:
25065.ma_console (14/12/12 14:48:52) (Detached)
1 Socket in /var/run/screen/S-root.
Ci-dessus, apparait la mention "Detached" signifiant qu'une console "ma_console" est en cours d'exécution en arrière plan.
Dans le cas où il y aurait plusieurs consoles.
$ sudo screen -ls
There are screens on:
25169.ma_console3 (14/12/12 14:54:51) (Detached)
25165.ma_console2 (14/12/12 14:54:45) (Detached)
25065.ma_console (14/12/12 14:48:52) (Detached)
3 Sockets in /var/run/screen/S-root.
Ci-dessus, apparait la liste de toutes les consoles en cours d'exécution avec leurs différents noms.
$ sudo screen -R 25065
Permet de retourner dans la console nommée "ma_console" et portant le pid "25065".
Il est important de préciser le pid de la console dans le cas où leurs noms seraient similaires (comme dans l'exemple ci-dessus : ma_console, ma_console2, ma_console3).
Sinon, le nom est suffisant.
$ sudo screen -R ma_console
Il est possible de créer une multitude de fenêtres en appuyant sur les touches ctrl + a puis sur c.
La liste des fenêtres créées apparaît en bas de l'écran (0$ bash 1$ bash 2$ bash 3-$ bash 4$ bash 5$ bash 6$ bash) en appyant sur les touches ctrl + a puis sur w.
Pour passer à la fenêtre suivante, appuyer sur les touches ctrl + a puis sur n (next).
Pour retourner à la fenêtre précédente, appuyer sur les touches ctrl + a puis sur p (previous).
Pour aller à une fenêtre en particulier, appuyer sur les touches ctrl + a puis sur le chiffre correspondant (voir la liste des fenêtres en bas de l'écran).
Dans une console screen, appuyer sur les touches ctrl + a puis sur shift + s
Une seconde fenêtre vide apparait au dessous.
Pour ouvrir une nouvelle console dans cette fenêtre vide, appuyer sur les touches ctrl + a puis sur tab.
Une fois le curseur dans la nouvelle fenêtre, appuyer sur les touches ctrl + a puis sur c.
Il est possible de spliter l'écran plusieurs fois si nécessaire.
Pour basculer d'un écran à l'autre appuyer sur les touches ctrl + a puis sur tab.
Pour supprimer la fenêtre en cours d'utilisation, appuyer sur les touches ctrl + a puis sur shift + x
Voici, à mon sens, les fonctions les plus utilses de la commande screen.
Personnalisation de screen
Il est possible de personnaliser screen avec un fichier de configuration nommé ~/.screenrc
Voici un fichier tout fait, créé par "bennyben" et que j'utilise personnellement.
Il customise vraiment bien la commande screen.
Son contenu est donc à enregistrer dans un fichier nommé ~/.screenrc
MD5SUM : a2aade4a2d4596b5df7720b3b3c3e904 screenrc.txt
Fichier attaché | Taille |
---|---|
Fichier de configuration de la commande screen | 5.94 Ko |
Le commande linuxlogo permet d'afficher dans la console de jolis logos colorisés en caractères ASCII.
Pour l'installer :
$ sudo apt-get install linuxlogo
Le manuel de la commande :
$ man linuxlogo
Exécution :
$ linuxlogo
Avec l'option -l, seul le logo est affiché
$ linuxlogo -l
Avec l'option -u, les informations uptime sont affichées.
$ linuxlogo -u
Avec l'option -y, les informations load average sont affichées.
$ linuxlogo -y
L'option -L list permet d'affiher la liste complète des logos disponibles.
$ linuxlogo -L list
Available Built-in Logos:
Pour afficher le logo souhaité :
$ linuxlogo -L numéro
Tous les logos disponible ICI.
La commande banner permet d'afficher dans la console un message de 10 caractères maximum avec uniquement des caractères "#".
Pour l'installer :
$ sudo apt-get install sysvbanner
Et ça donne ceci :
$ banner Linux
Il existe également la commande printerbanner mais l'affichage se fait verticalement.
decrypt.py est un programme écrit en python qui anime la console en lui donnant un effet "Matrix"
L'animation générée est vraiment très sympa.
Le script peut être téléchargé ICI
Sinon, en ligne de commande :
Avec git :
$ git clone https://github.com/jtwaleson/decrypt.git
ou en téléchargeant le fichier ZIP :
$ wget https://github.com/jtwaleson/decrypt/archive/master.zip
$ unzip master.zip
Copier le script decrypt.py dans le répertoire /usr/local/bin
$ cp decrypt.py /usr/local/bin/
Exécution :
Afficher le contenu d'un fichier
$ cat decrypt.py | decrypt.py
Voir la vidéo : http://youtu.be/xI3JQg5BVtI
Lister le contenu d'un répertoire
$ ls -l | decrypt.py
Voir la vidéo : http://youtu.be/QnljP35j5EQ
Avec une image en ASCII (convertie avec la commande jp2a)
$ jp2a erreur404.jpg | decrypt.py
Voir la vidéo : http://youtu.be/8CAtUdl4Q5I
eyeD3 est un outil python qui permet de visualiser/créer les tags ID3 des fichiers MP3.
Ce programme s'utilise uniquement en ligne de commande.
$ apt-get install eyeD3
ou
$ apt-get install python-eyeD3
$ eyeD3 monFichier.mp3
$ eyeD3 -a "Nom Artiste" monFichier.mp3
$ eyeD3 -A "Nom Album" monFichier.mp3
$ eyeD3 -t "Titre Chanson" monFichier.mp3
$ eyeD3 -n 1 monFichier.mp3
$ eyeD3 -N 10 monFichier.mp3
$ eyeD3 --list-genres
$ eyeD3 -G "Pop / Funk" monFichier.mp3
$ eyeD3 -Y 2015 monFichier.mp3
$ eyeD3 --list-image-types
$ eyeD3 --add-image=/chemin/vers/image:TYPE[:DESCRIPTION] monFichier.mp3
TYPE correspond au type d'image à insérer (voir commande du dessus). Une description optionnelle peut être ajoutée.
Pour supprimer une image, il suffit d'indiquer le type correspondant sans renseigner d'image.
$ eyeD3 -h
$ wget http://eyed3.nicfit.net/releases/eyeD3-X.Y.Z.tgz
$ tar -xvzf eyeD3-X.Y.Z.tgz
$ cd eyeD3-X.Y.Z
$ python setup.py install
import eyed3
audiofile = eyed3.load("chanson.mp3")
audiofile.tag.artist = u"Artiste"
audiofile.tag.album = u"Album"
audiofile.tag.title = u"Titre"
audiofile.tag.track_num = 4
audiofile.tag.save()
Plus d'info sur http://eyed3.nicfit.net/
jp2a est une commande qui permet d'afficher dans la console une image JPG en caractères ASCII.
Pour l'installer :
$ sudo apt-get install jp2a
Convertir une image :
$ jp2a erreur404.jpg
Ce qui donne :
L'effet est vraiment bluffant sur certaines photos.
La conversion ne se fait que sur des fichiers JPG.
Pour convertir une image PNG en JPG utiliser la commande convert de ImageMagick :
$ convert image.png image.jpg
ou
$ convert image.png jpg:- | jp2a -
Cette dernière commande permet de convertir l'image PNG en JPG directement sur la sortie standard afin de la transmettre à la commande jp2a via son entrée standard.
Imagemagick est un logiciel ultra-puissant qui s'utilise en ligne de commande et qui permet de manipuler quasiment tous les types d'images.
Convertion, redimensionnement, rotation, fusion, animation etc etc ... sont quelques unes des fonctions proposées par Imagemagick.
Pour installer imagemagick :
$ sudo apt-get install imagemagick
Convertir une vidéo AVI en GIF animé
$ convert -quiet -delay 1 input.avi +map output.gif
Pour convertir une vidéo MOV en GIF animé.
Remplacer le fond blanc d'une image en fond transparent
$ convert test.png -transparent white transparent.png
Convertir une image png en jpg et inversement
$ convert image.png image.jpg
Convertir une série d'images png en jpg et inversement
$ for f in *.png; do convert $f $(echo $f | cut -d. -f1).jpg; done
ou
$ mogrify -format jpg *.png
Modifier le taux de compression pendant la conversion
$ mogrify -quality 90 -format jpg *.png
Convertir une série d'image jpg (ou tout autre format) en gif animé
$ convert *.jpg anime.gif
Ajouter l'option -delay num pour paramétrer la vitesse d'animation du gif animé.
num est exprimé en 1/100 seconde.
Ajouter l'option -loop num pour paramétrer le nombre de boucle.
Par défaut -loop 0 (infini).
Convertir et redimensionner une image
$ convert image.jpg -resize 50% image.png
ou en indiquant une taille en pixel
$ convert -resize 800x600 image.png image.jpg
ou en indiquant seulement la largeur (maxi) en pixel (le ratio est conservé)
$ convert -resize 800x image.png image.jpg
ou seulement la hauteur (maxi) en pixel (le ratio est conservé)
$ convert -resize x600 image.png image.jpg
et toutes les images d'un dossier avec la commande mogrify
$ mogrify -resize 800x600 -format jpg *.png
Créer une icône à partir d'une image
$ convert -colors 256 -resize 16x16 image.jpg icone.ico
Convertir une image en niveau de gris
$ convert -type Grayscale image.jpg image.grayscale.jpg
Les différents types disponibles
$ convert -list type
Bilevel
ColorSeparation
ColorSeparationAlpha
ColorSeparationMatte
Grayscale
GrayscaleAlpha
GrayscaleMatte
Optimize
Palette
PaletteBilevelAlpha
PaletteBilevelMatte
PaletteAlpha
PaletteMatte
TrueColorAlpha
TrueColorMatte
TrueColor
Un exemple de chaque type est disponible ici.
Ajouter une bordure à une image
Une bordure transparente d'1 pixel
$ convert -bordercolor Transparent -border 1x1 image.jpg image-bordure.jpg
Une bordure noire de 10 pixels
$ convert -bordercolor black -border 10x10 image.jpg image-bordure.jpg
Créer le négatif d'une image
$ convert -negate image.jpg negate.jpg
Retourner une image verticalement
$ convert -flip image.jpg flip.jpg
Utiliser -flop pour retourner l'image horizontalement.
Pivoter une image vers la droite
$ convert -rotate 90 source.jpg destination.jpg
Utiliser -90 pour pivoter l'image vers la gauche.
Ajouter un texte en haut à gauche sur plusieurs images
$ mogrify -fill white -pointsize 16 -annotate +10+26 'Copie Interdite' *.jpg
-fill white : couleur du texte
-pointsize 16 : dimension du texte en pixel
-annotate +10+26 : position du texte sur l'image (verticale/horizontale)
Pour la position horizontale du texte, tenir compte de la dimension du texte.
Faire un montage avec plusieurs images
$ montage -background "azure3" *.jpg montage.jpg
Avec l'option -geometry, il est possible de modifier la taille des bordures entre chaque image.
La commande suivante ajoute une bordure de 5 pixels entre chaque image
$ montage -geometry +5+5 *.jpg montage.jpg
Avec l'option -resize, il est possible de redimensionner les images à assembler.
La commande suivante réduit la taille de chaque image de 80% avant de les assembler.
$ montage -resize 20% *.jpg montage.jpg
Extraire une partie d'une image
$ convert image.jpg -crop XxY+L+T newImage.jpg
X : Largeur de la nouvelle image
Y : Hauteur de la nouvelle image
L : Point de départ à gauche de l'image d'origine
T : Point de départ du haut de l'image d'origine
Par exemple, dans le schéma ci-dessous, pour extraire l'image B (500x300) de l'image A (800x600) à partir du point L (20 px à partir du bord gauche) et du point T (15 px à partir du bord haut)
$ convert image.jpg -crop 500x300+20+15 newImage.jpg
Même traitement mais sur plusieurs images
$ for f in *.png; do convert $f -crop 500x300+20+15 new_$f; done
Convertir des images png (ou autres) en un fichier pdf (avec compression des images en jpeg)
Attention, suite à une faille de sécurité, cette conversion n'est plus possible à moins de modifier un paramètre dans le fichier policy.xml de ImageMagick. Plus d'info ici.
Merci à Sergio pour l'info.
$ convert *.png -compress jpeg monDoc.pdf
Et inversement :
$ convert -density 500 monDoc.pdf monDoc.jpg
Afficher la liste de toutes les couleurs disponibles
$ convert -list color
Générer les échantillons de toutes les couleurs gérées par ImageMagick
$ for liste in $(convert -list color | sed '1,5d' | awk '{print $1 "|" $2}'); do couleur=$(cut -d'|' -f1 <<< $liste); code=$(cut -d'|' -f2 <<< $liste); convert -size 50x50 xc:"$code" $couleur.png; done
Cet enchainement de commandes permet de générer des images PNG de 50px de toutes les couleurs dans le dossier courant. Tous les fichiers sont nommés par leur nom de couleur.
Exemple des images générées : http://isbeta.fr/4f2fc
Centrer une image dans un calque :
La commande suivante permet de créer un calque transparent d'une taille de 100 x 100 pixels et d'y insérer, au centre, une image proportionnellement redimensionnée à la taille du calque
$ convert img.png -resize 100x100 -size 100x100 xc:none +swap -gravity center -composite new_img.png
Par exemple :
Image d'origine
Image redimensionnée et centrée dans le calque
Réaliser une vidéo à partir d'images
$ convert -delay 25 *.jpg anim.mpg
-delay 25 = 25 images par seconde
Afficher les informations d'une image
$ identify image.jpg
Avec plus de détail
$ identify -verbose image.jpg
Créer une image à partir d'un texte
$ convert -background white -fill black -font "Cretino-Regular" -pointsize 30 -size 200x -gravity Center caption:"Mon texte." "e.gif"
$ display e.gif
Créer une image à partir d'un texte contenu dans un fichier
$ cat texte
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec sed finibus dui. Interdum et malesuada fames ac ante ipsum primis in faucibus. Quisque ultrices erat in tempor aliquam. Ut ut facilisis lectus. Sed bibendum pellentesque urna, nec convallis massa.
$ convert -background "rgb(169,169,169)" -fill "rgb(255,255,255)" -font "Abecedario_pautada-Regular" -pointsize 40 -size 480x -gravity Center caption:"$(cat texte)" "d.gif"
$ display d.gif
Souvenir d'école
Le site du projet ffmpeg : http://www.ffmpeg.org/
Pour installer FFmpeg :
$ sudo apt-get install ffmpeg
Depuis Ubuntu 14.04, ffmpeg n'est plus dans les dépôts Ubuntu.
Pour l'installer, sans passer par les dépôts, il suffit de télécharger le dernière version du programme sur le site officiel :
... puis décompresser l'archive téléchargée :
$ tar -xzf ffmpeg.static.[32|64]bit.latest.tar.gz
... puis copier les deux fichiers ffmpeg et ffprobe dans le répertoire /usr/local/bin :
$ sudo cp ffmpeg ffprobe /usr/local/bin
... et voilà, c'est terminé.
Pour vérifier la version installée :
$ ffmpeg -version
Pour incruster une image dans une vidéo, il suffit d'utiliser le filtre overlay avec la commande ffmpeg.
Par exemple, pour ajouter un logo en bas, à droite :
$ ffmpeg -i movie.mp4 -i logo.png -filter_complex "overlay=W-w-5:H-h-5" -b:v 3000k -s 720x480 -codec:v h264 -fs 20M movie_avec_logo.mp4
Détail des options :
-b:v permet d'indiquer le bitrate
-s permet d'indiquer les dimensions
-codec:v permet d'indiquer le codec vidéo à utiliser
-fs permet d'indiquer la taille maxi du fichier généré
-i permet d'indiquer tous les fichiers à traiter en entrée
-filter_complex permet d'utiliser les filtres disponibles
Détail du filtre overlay :
Pour utiliser le filtre overlay, il suffit de lui indiquer les positions horizontale et verticale à utliser pour insérer l'image ou la vidéo.
Pour insérer un logo en haut à gauche :
overlay=0:0
Avec un décalage de 5 px des bords gauche et haut :
overlay=5:5
Il est possible d'utiliser les variables W, w, H et h qui correspondent à :
W : Largeur (width) de la vidéo principale
H : Hauteur (height) de la vidéo principale
w : Largeur (width) de l'image ou de la vidéo à incruster
h : Hauteur (height) de l'image ou de la vidéo à incruster
Donc, pour incruster une image en bas, à droite avec un décalage de 5 px des bords bas et droite :
overlay=W-w-5:H-h-5
Résultat :
Lister les codecs vidéos :
$ ffmpeg -codecs | grep DEV
Lister les codecs audios :
$ ffmpeg -codecs | grep DEA
Convertir une vidéo mpeg4 en GIF animé :
$ ffmpeg -i input.mp4 -vf scale=356:-1 -r 10 -f image2pipe -vcodec ppm - | convert -delay 10 -loop 0 - gif:- | convert -layers Optimize - output.gif
Convertir une vidéo MOV en GIF animé :
1 - Conversion de la vidéo MOV à l'aide de la commande ffmpeg
$ ffmpeg -i input.mov -pix_fmt rgb24 output_tmp.gif
2 - Amélioration du GIF animé à l'aide de la commande convert
$ convert -layers output_tmp.gif output.gif
Convertir des images JPG/PNG en GIF animé:
$ convert -delay 20 -loop 0 *.JPG result.gif
Pour varier la vitesse du GIF animé, augmenter/diminuer la valeur du paramètre -delay
Extraire une partie d'une vidéo :
$ ffmpeg -i MOV.mp4 -ss 00:00:25 -t 00:00:10 MOV1.mp4
Cette commande permet d'extraire 10 secondes à partir de la 25ème seconde
-ss : Début de l'extraction
-t : Durée de l'extraction
Ralentir (effet slow motion) une vidéo :
$ ffmpeg -i MOV.mp4 -vf "setpts=8*PTS" MOV5.mp4
Plus le coefficient multiplicateur est élevé, plus la vidéo est ralentie.
1 étant le coefficient de base.
Accélérer une vidéo :
$ ffmpeg -i MOV.mp4 -vf "setpts=0.2*PTS" MOV5.mp4
Encoder une vidéo en 2 passes :
$ for P in 1 2; do ffmpeg -y -i MOV.mp4 -b:v 3000k -pass $P -r 30 -c:v h264 -c:a mp3 -b:a 128k -s 1024*768 MOV.avi; done
-b:v 3000k : Permet de régler le bitrate de la vidéo
-r 30 : Permet de définir le nombre d'images par seconde
-pass $P : Permet d'indiquer le numéro de la passe à effectuer
-c:v h264 : Permet d'indiquer le codec vidéo à utiliser
-c:a mp3 : Permet d'indiquer le codec audio à utiliser
-s 1024*768 : Permet d'indiquer la taille de la vidéo
-b:a 128k : Permet de régler le bitrate audio
Pivoter une vidéo :
$ ffmpeg -i MOV.mp4 -vf "transpose=1" MOV1.mp4
-vf "transpose=1" : Permet de faire pivoter la vidéo de 90 degrés vers la droite
-vf "transpose=2" : Permet de faire pivoter la vidéo de 180 degrés vers la droite
etc etc ...
Effet miroir :
$ ffmpeg -i MOV.mp4 -vf "hflip" MOV1.mp4
-vf "hflip" : Effet miroir horizontal
-vf "vflip" : Effet miroir vertical
Assembler plusieurs vidéos en un seul fichier :
$ ffmpeg -i "concat:MOV1.avi|MOV2.avi|MOV3.avi|MOV4.avi" -c copy MOV_0005.avi
-c copy : Permet d'indiquer de ne pas réencoder les vidéos
Conversion FLV To AVI :
$ ffmpeg -i mavideo.flv mavideo.avi
Conversion AVI To FLV :
$ ffmpeg -i mavideo.avi mavideo.flv
Conversion MP3 To WAV :
$ ffmpeg -i monFichier.mp3 monFichier.wav
Extraire toutes les images d'une vidéo :
$ ffmpeg -i foo.avi -r 1 -s WxH -f image2 foo-%03d.jpeg
-s WxH -> dimensions des images générées
-f image2 -> format de sortie
-r 1 -> fréquence d'images : 1 image par seconde
Créer une vidéo à partir de plusieurs images :
$ ffmpeg -f image2 -i foo-%03d.jpeg -r 12 -s WxH foo.avi
-r 12 -> fréquence d'images : 12 images par seconde
-s WxH -> dimension de la vidéo générée
-f image2 -> format du/des fichiers en entrée
Pour installer MEncoder:
$ sudo apt-get install mencoder (installation automatique des dépendances requises)
Lister tous les codecs audios supportés par MEncoder :
$ mencoder -oac help
Lister tous les codecs vidéos supportés par MEncoder :
$ mencoder -ovc help
Lister tous les formats vidéos de sortie supportés par MEncode :
$ mencoder -of help
AVI étant le format par défaut de MEncoder et le mieux supporté
Pour convertir des images au format JPG en une séquence vidéo au format AVI :
$ mencoder -ffourcc XVID mf://*.jpg -mf w=800:h=600:fps=25:type=jpg -ovc lavc -lavcopts vcodec=mpeg4 -oac copy -o output.avi
Pour convertir une vidéo au format AVI en utilisant le codec de compression MJPEG :
$ mencoder fichier_in.avi -oac copy -ovc lavc -lavcopts vcodec=mjpeg -o fichier_out.avi
Pour convertir une vidéo au format AVI vers le format FLV permettant sa lecture dans un navigateur internet avec le plugin Macromedia Flash :
$ mencoder input.avi
-o output.flv
-of lavf -oac mp3lame -lameopts abr:br=56 -ovc lavc \ -lavcopts vcodec=flv:vbitrate=500:mbd=2:mv0:trell:v4mv:cbp:last_pred=3 \ -srate 22050
Conversion WMV To MPEG-4 (Xvid) :
$ mencoder mavideo.wmv -ovc xvid -oac mp3lame -o mavideo.avi
Conversion FLV To AVI (MPEG-4/Divx) en 2 passes :
$ mencoder video.flv -ovc lavc -lavcopts vcodec=mpeg4:vpass=1 -oac copy -o a.avi
$ mencoder video.flv -ovc lavc -lavcopts vcodec=mpeg4:vpass=2 -oac copy -o a.avi
transcode est un programme de traitement vidéo.
Pour l'installer :
$ sudo apt-get install transcode
Il permet de faire énormément de choses mais mon option préférée est celle qui permet de stabiliser une vidéo.
Le résultat est vraiment très surprenant.
Exemple :
Pour stabiliser une vidéo, il faut d'abord que transcode analyse la vidéo source...
$ transcode -J stabilize -i movie.avi
Cette commande va générer un fichier trf.
Ajouter l'option --mplayer_probe pour utiliser le programme mplayer pour l'analyse si le format de la vidéo n'est pas directement supporté par transcode.
... et enfin, pour stabiliser la vidéo :
$ transcode -J transform --mplayer_probe -i movie.avi -y raw -o movie_stabilize.avi
Attention, la taille de la vidéo générée est très volumineuse avec le format raw.
Il est possible d'indiquer un codec vidéo pour l'encodage final :
$ transcode -J transform --mplayer_probe -i movie.avi -y xvid4 -o movie_stabilize.avi
La preuve en image :
A gauche, la vidéo d'origine, à droite, après stabilisation.
Surprenant, non ?
Editer le fichier /etc/apt/apt.conf
Pour un proxy sans authentification
Acquire::http::Proxy "http://IP.DU.PROXY:PORT";
Pour un proxy avec authentification
Acquire::http::Proxy "http://user:passwd@IP.OU.NOM.DNS.DU.PROXY:PORT";
Saisir dans une console
$ http_proxy="http://user:passwd@IP.OU.NOM.DNS.DU.PROXY:PORT" sudo apt-get update
Saisir dans une console
$ export http_proxy="http://user:passwd@IP.OU.NOM.DNS.DU.PROXY:PORT"
$ sudo apt-get update
$ sudo apt-get install mon_paquet...
installer les paquets smbclient & cifs-utils
$ apt-get install smbclient
$ apt-get install cifs-utils
Monter un partage via la console :
$ mount -t cifs //adresse_ip_du_serveur/nom_du_partage /point_de_montage --verbose -o user=user_samba,password=password_samba
Pour monter automatiquement les partages Samba de Ubuntu Server sur Ubuntu Desktop avec une identification
Editer le fichier /etc/fstab
$ sudo -s
$ gedit /etc/fstab
Y rajouter la ligne suivante pour un partage nommé public sur Ubuntu Server
//adresse_ip_du_serveur/public /home/user/Public smbfs _netdev,credentials=/home/user/.smbcredentials,iocharset=utf8 0 0
Explications :
//adresse_ip_du_serveur/public : adresse et nom du partage Samba sur le serveur
/home/user/Public : destination du montage
smbfs : type du montage (Samba)
_netdev : permet d'attendre que la connexion réseau soit effective avant d'effectuer le montage
credentials=/home/user/.smbcredentials : chemin et nom du fichier permettant l'identification
iocharset=utf8 : permet la prise en charge des caractères accentués
Création du fichier d'identification .smbcredentials
$ gedit /home/user/.smbcredentials
Y inscrire les informations suivantes
username=USERNAME
password=PASSWORD
Pour les partages Samba comportant un espace
Par exemple, pour accéder au partage Samba "Mes images" inscrire la ligne suivante dans le fstab
//adresse_ip_du_serveur/Mes\040images /home/user/Images smbfs _netdev,credentials=/home/user/.smbcredentials,iocharset=utf8 0 0
La chaîne de caractères "\040" correspond au caractère "espace"
Pour quitter une console, il existe différentes manières de le faire.
Avec la commande exit :
$ exit
Avec les touches ctrl+d (^D) ;
$ ^d # Saisie clavier ctrl+d
Pour effectuer une sauvegarde différentielle, il faut utiliser le programme rdiff-backup.
Pour l'installer :
$ sudo apt-get install rdiff-backup
Pour créer une sauvegarde différentielle
$ rdiff-backup /repertoire_a_sauvegarder /repertoire_de_sauvegarde
Sauvegarder sur une machine distante via
SSHRemplacer
Par
Pour supprimer une sauvegarde différentielle
$ rdiff-backup --remove-older-than 1W --force /repertoire_de_sauvegarde
Ici on enlève toutes les modifications enregistrées vieilles de plus d'une semaine. On peut mettre D(ay)
,W(eek)
, M(onth)
et Y(ear)
.
S'il y a plusieurs sauvegardes à supprimer, la commande échoue. C'est pourquoi il faut rajouter le paramètre –force
pour ne pas prendre cette erreur en compte et que rdiff-backup effectue bien ce qu'on lui demande.
Pour afficher l'état d'une sauvegarde différentielle en liste simple
$ rdiff-backup -l /repertoire_de_sauvegarde
Pour afficher l'état d'une sauvegarde différentielle en tableau avec la taille de chaque incrément:
$ rdiff-backup --list-increment-size /repertoire_de_la_sauvegarde
Pour enregistrer le résultat dans un fichier :
$ rdiff-backup --list-increment-size /repertoire_de_la_sauvegarde > /repertoire/etat_sauvegarde.txt
Voir les statistiques des sauvegardes
$ rdiff-backup-statistics /repertoire_de_sauvegarde
Pour restaurer une sauvegarde différentielle
$ rdiff-backup -r now /repertoire_de_sauvegarde /repertoire_de_restauration
L'option -r now
permet de remettre la version de la sauvegarde la plus récente. On peut remonter dans les sauvegardes, par exemple remettre le repertoire d'il y a 3 jours avec l'option -r 3D
.
Rdiff-backup fait une replication parfaite des fichiers dans leur dernière version. Ainsi pour restaurer des données, il suffit de faire
$ cp -a /backupDir /restoredDir
Pour connaitre la version du noyau en cours d'utilisation, saisir dans une console la commande suivante :
$ sudo uname -a
Linux vm-apache 2.6.32-14-pve #1 SMP Tue Aug 21 08:24:37 CEST 2012 i686 GNU/Linux
Sur un système GNU/Linux, une locale qui n'est pas correctement configurée entraîne ce genre de message d'erreur :
-bash: warning: setlocale: LC_CTYPE: cannot change locale (en_GB.UTF-8)
-bash: warning: setlocale: LC_CTYPE: cannot change locale (en_GB.UTF-8)
Pour corriger cette erreur, il suffit d'exécuter les 2 commandes suivantes :
$ sudo locale-gen en_GB.UTF-8
$ sudo update-locale LANG=en_GB.UTF-8
Une simple déconnexion / reconnexion suffit pour ne plus avoir le problème.
Sous Linux, la vérification des disques s'effectue avec la commande fsck.
L'utilisation de cette commande nécessite que la partition à controler soit démontée.
Lister les disques et partitions du système
$ fdisk -l
Disk /dev/sdb: 1500.3 GB, 1500299395072 bytes
255 heads, 63 sectors/track, 182401 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00026d5d
Device Boot Start End Blocks Id System
/dev/sdb1 1 182401 1465136001 83 Linux
Identifier le type de la partition
$ blkid
/dev/sdb1: UUID="a6ea6463-e289-4bbe-afba-572f876497da" TYPE="ext4"
Identifier le point de montage de la partition
$ mount
/dev/sdb1 on /volume1 type ext4 (rw)
Démonter la partition et lancer la vérification
$ umount /volume1
$ fsck -t ext4 /dev/sdb1
Si le démontage de la partition n'est pas possible, il existe 2 solutions permettant la vérification des disques.
1 - Redémarrer le système en forçant la vérification :
$ shutdown -r -F now
2 - Créer le fichier forcefsck et redémarrer le système :
$ touch /forcefsck
$ reboot
Après le redémarrage et la vérification des disques, le fichier /forcefsck est automatiquement supprimé.
Par défaut, les pages de manuels utilisent la commande less pour les afficher.
La commande less est une évolution de la commande more.
Elle permet de mettre en gras les rubriques principales des pages de manuels.
La commande most, permet d'ajouter une coloration syntaxique et bien d'autres options supplémentaires.
Pour installer la commande most :
$ sudo apt-get install most
Pour utiliser most pour parcourir les pages de manuels :
$ PAGER=most man cp
Cette commande permet d'utiliser most comme PAGER pour consulter le manuel de la commande cp
Pour utiliser most comme PAGER par défaut :
En BASH, ajouter cette ligne dans le fichier ~/.bashrc
export PAGER=most
Autres options disponibles avec la commande most (partant du principe que most est le PAGER par défaut):
Non seulement most permet de consulter les pages de manuels mais il peut également afficher le contenu de n'importe quel fichier.
$ man cp # consultation du manuel avec la commande most si PAGER par défaut
$ most /mon_fichier
H : affichage de l'aide most
Espace ou D : défilement page par page vers le bas
Delete ou U : défilement page par page vers le haut
Entrée ou Flèche bas : défilement ligne par ligne vers le bas
Flèche haut : défilement ligne par ligne vers le haut
T : se positionne en haut du document
B : se positionne en bas du document
J ou G : se positionne à la ligne voulue
> : déplacement vers la droite
< : déplacement vers la gauche
S ou f ou / : permet d'effectuer une recherche vers le bas
? : permet d'effectuer une recherche vers le haut
N : recherche les occurences suivantes
En mode affichage de fichier :
E : bascule en mode édition avec l'éditeur par défaut
En mode affichage de logs en continu :
au lieu de
$ tail -f /var/log/access.log
utiliser most puis l'option F
$ most /var/log/access.log
F : simule la commande tail -f
La commande suivante permet d'afficher les 15 premiers processus les plus gourmands en processeur.
$ sudo ps auxk -pcpu | head -n 16
$ sudo ps -ef | grep nom_du_programme
ou
$ pgrep nom_du_programme
La commande ci-dessus retourne le numéro du processus recherché.
Afficher les processus d'un user particulier (par exemple root):
$ pgrep -u root
Pour afficher les statistiques d'un programme spécifique à l'aide de la commande top:
L'exemple suivant affiche tous les processus nginx.
$ top -p$(pgrep -d, nginx)
L'argument -d de la commande pgrep permet d'afficher les numéros des processus séparés par une virgule.
L'argument -p de la commande top permet de filtrer uniquement les processus indiqués.
La commande logger permet d'enregistrer des informations dans le fichier /var/log/syslog.
Cette commande est idéale pour journaliser différents évènements pendant l'exécution d'un script.
Elle peut être utilisée tout simplement :
$ logger -t monTag monMessage
$ tail /var/log/syslog
Apr 23 15:23:37 ubuntu10.04 monTag: monMessage
L'option -t permet d'indiquer un tag. Très utile pour effectuer des recherches dans le fichier syslog.
$ logger -t monTag Je peux également écrire un texte avec des espaces
$ tail /var/log/syslog
Apr 23 15:26:12 ubuntu10.04 monTag: Je peux également écrire un texte avec des espaces
La commande logger permet également d'enregistrer dans syslog le contenu d'un fichier.
$ cat fic1
systèmes
coucou
recoucou
$ logger -t FIC1 -f fic1
$ tail /var/log/syslog
Apr 23 15:29:13 ubuntu10.04 FIC1: systèmes
Apr 23 15:29:13 ubuntu10.04 FIC1: coucou
Apr 23 15:29:13 ubuntu10.04 FIC1: recoucou
Utiliser la commande logger dans un script :
$ cat comparaison.sh
#!/bin/bash
logger -t $0 Execution du script
# Test sur le nombre d'arguments
if [[ $# -ne 2 ]]
then
logger -t $0 Nombre d\'arguments incorrect
echo "Mauvais nombre d'arguments"
echo "Utilisation : $0 nbr1 nbr2"
exit 1
fi
# On compare les nombres
logger -t $0 Comparaison de $1 et $2
if [[ $1 -gt $2 ]]
then
logger -t $0 $1 est superieur a $2
echo "Comparaison : $1 est superieur a $2"
else
logger -t $0 $1 est inferieur a $2
echo "Comparaison : $1 est inferieur a $2"
fi
logger -t $0 Fin du script
exit 0
Dans ce script, j'utilise le nom du script comme tag (logger -t $0).
Exécution du script :
$ ./comparaison.sh 10 20
Comparaison : 10 est inferieur a 20
$ tail /var/log/syslog
Apr 23 15:51:57 ubuntu10.04 ./comparaison.sh: Execution du script
Apr 23 15:51:57 ubuntu10.04 ./comparaison.sh: Comparaison de 10 et 20
Apr 23 15:51:57 ubuntu10.04 ./comparaison.sh: 10 est inferieur a 20
Apr 23 15:51:57 ubuntu10.04 ./comparaison.sh: Fin du script
Tous mes évènements ont été enregistrés dans sylog.
Il est également possible, dans le script, d'enregistrer les évènements dans un fichier texte avec la commande echo et seulement, à la fin du script, d'utiliser la commande logger pour enregistrer le contenu du fichier texte dans le fichier syslog.
$ cat comparaison.sh
#!/bin/bash
echo "Execution du script" > /root/logComparaison
# Test sur le nombre d'arguments
if [[ $# -ne 2 ]]
then
echo "Nombre d'arguments incorrect" >> /root/logComparaison
echo "Mauvais nombre d'arguments"
echo "Utilisation : $0 nbr1 nbr2"
exit 1
fi
# On compare les nombres
echo "Comparaison de $1 et $2" >> /root/logComparaison
if [[ $1 -gt $2 ]]
then
echo "$1 est superieur a $2" >> /root/logComparaison
echo "Comparaison : $1 est superieur a $2"
else
echo "$1 est inferieur a $2" >> /root/logComparaison
echo "Comparaison : $1 est inferieur a $2"
fi
echo "Fin du script" >> /root/logComparaison
logger -t $0 -f /root/logComparaison
exit 0
Tous les évènements sont enregistrés dans le fichier /root/logComparaison à l'aide de la commande echo.
Attention, le premier appel à la commande echo écrase le contenu du fichier /root/logComparaison s'il existe (utilisation d'un seul chevron ">" dans la redirection).
Pour terminer, tout le contenu du fichier est enregistré dans syslog à l'aide de la commande logger et de l'option -f suivi du nom du fichier (utilisation du nom du script en tag).
$ ./comparaison.sh 100 20
Comparaison : 100 est superieur a 20
$ cat logComparaison
Execution du script
Comparaison de 100 et 20
100 est superieur a 20
Fin du script
$ tail /var/log/syslog
Apr 23 16:21:10 ubuntu10.04 ./comparaison.sh: Execution du script
Apr 23 16:21:10 ubuntu10.04 ./comparaison.sh: Comparaison de 100 et 20
Apr 23 16:21:10 ubuntu10.04 ./comparaison.sh: 100 est superieur a 20
Apr 23 16:21:10 ubuntu10.04 ./comparaison.sh: Fin du script
Pour connaitre la version d'Ubuntu installée sur le système, saisir dans une console la commande suivante :
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 10.04.4 LTS
Release: 10.04
Codename: lucid
L'information concernant la version installée apparait à la ligne Description
Sinon, il y a le fichier /etc/issue (fonctionne avec Ubuntu et Debian)
$ file /etc/issue
/etc/issue: ASCII text
$ cat /etc/issue
Debian GNU/Linux 6.0 \n \l
$ cat /etc/issue
Ubuntu 10.04.4 LTS \n \l
Il y a également le fichier /etc/debian_version
$ file /etc/debian_version
/etc/debian_version: ASCII text
$ cat /etc/debian_version
squeeze/sid
Enfin, il y a le fichier /etc/lsb-release (informations fournies avec la commande lsb_release -a)
$ file /etc/lsb-release
/etc/lsb-release: ASCII text
$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=10.04
DISTRIB_CODENAME=lucid
DISTRIB_DESCRIPTION="Ubuntu 10.04.4 LTS"
Pour connaitre la version du noyau Linux, saisir dans une console la commande suivante :
$ uname -a
Linux vm-apache 2.6.32-14-pve #1 SMP Tue Aug 21 08:24:37 CEST 2012 i686 GNU/Linux
Pour arrêter un serveur Ubuntu, saisir la commande suivante dans une console
$ sudo halt
Ou en utilisant la commande shutdown :
$ sudo shutdown -h now
L'indication now permet un arrêt immédiat.
Pour un arrêt dans 1 minute :
$ sudo shutdown -h +1 &
Pour un arrêt à une heure précise :
$ sudo shutdown -h 16:50 &
Pour annuler un arrêt programmé :
$ sudo shutdown -c
Dans le cas d'un arrêt programmé, un message est envoyé toutes les minutes à tous les utilisateurs connectés au système pour annoncer l'arrêt.
Pour redémarrer un serveur Ubuntu, saisir la commande suivante dans une console
$ sudo reboot
Ou en utilisant la commande shutdown :
$ sudo shutdown -r now
L'indication now permet un redémarrage immédiat.
Pour un redémarrage dans 1 minute :
$ sudo shutdown -r +1 &
Pour un redémarrage à une heure précise :
$ sudo shutdown -r 16:50 &
Pour annuler un redémarrage programmé :
$ sudo shutdown -c
Dans le cas d'un redémarrage programmé, un message est envoyé toutes les minutes à tous les utilisateurs connectés au système pour annoncer le redémarrage.
J'ai souvent rencontré sur mes VMs Ubuntu Server cette erreur :
perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
LANGUAGE = (unset),
LC_ALL = (unset),
LANG = "fr_FR.UTF-8"
are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").
J'ai donc tenté une re-configuration des locales :
$ dpkg-reconfigure locales
perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
LANGUAGE = (unset),
LC_ALL = (unset),
LANG = "fr_FR.UTF-8"
are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").
locale: Cannot set LC_CTYPE to default locale: No such file or directory
locale: Cannot set LC_MESSAGES to default locale: No such file or directory
locale: Cannot set LC_ALL to default locale: No such file or directory
Sans succès.
Pour corriger cette erreur, il faut utiliser la commande locale-gen :
$ locale-gen fr_FR.UTF-8
Generating locales...
fr_FR.UTF-8... done
Generation complete.
Puis lancer la re-configuration des locales :
$ dpkg-reconfigure locales
Generating locales...
fr_FR.UTF-8... up-to-date
Generation complete.
Pour forcer Ubuntu Server à prendre en compte la langue française avec un encodage de caractères en UTF-8, il faut installer le package language-pack-fr, indiquer dans le fichier /etc/default/locale la valeur fr_FR.UTF-8 à la variable LANG puis lancer une reconfiguration du système.
$ apt-get install language-pack-fr
$ if [ -f /etc/default/locale ]; then cp /etc/default/locale /etc/default/locale_default; fi
$ echo "LANG=fr_FR.UTF-8" > /etc/default/locale
$ cat /etc/default/locale
LANG=fr_FR.UTF-8
$ dpkg-reconfigure locales
Les modifications seront effectives à la prochaine connexion.
Source : http://www.aepik.net/documentation/ubuntu/server/locales
GPG (GnuPG), abréviation de GNU Privacy Guard est un outil qui permet d'envoyer des messages signés et/ou chiffrés.
Dans le cas de messages signés, cela permet au destinataire de savoir exactement que le message qu'il reçoit a bien été envoyé par l'expéditeur indiqué et qu'il n'a pas été altéré.
Dans le cas de messages chiffrés, seul le destinataire du message est en mesure de le déchiffrer. Même l'expéditeur ne peut pas le faire.
Pour fonctionner, GPG utilise un système de paire de clés.
L'association d'une clé privée et d'une clé publique.
Comme son nom l'indique, la clé privée est privée et ne doit surtout pas être divulgée.
La clé publique, quant à elle, doit obligatoirement être communiquée à toutes les personnes avec lesquelles vous souhaitez communiquer de manière sécurisée (chiffrée).
Pour cela, il existe des serveurs de clés publiques où n'importe qui est en mesure de récupérer la clé publique de n'importe qui.
Plus d'infos sur Wikipédia
Le site de GnuPG
Infographie conçue par la FSF
Une version de GnuPG est disponible pour Android, sur Google Play.
Une extension, Enigmail, est disponible pour le logiciel de messagerie Thunderbird.
Une extension, Mailvelope, est disponible pour les navigateurs Firefox et Chrome.
La personne "A" souhaite communiquer de manière sécurisée avec la personne "B" et inversement.
Chacun de leur coté, "A" et "B" génèrent leurs clés privées et publiques et publient leurs clés publiques sur un serveur de clés.
"A" recherche sur le serveur de clés la clé publique de "B".
"A" rédige un message dans un fichier, le signe et le chiffre à l'aide de la clé publique de "B".
Un nouveau fichier est généré mais le contenu de celui-ci est chiffré.
"A" envoie ce fichier par mail à "B".
"B" reçoit de "A" un mail (automatiquement signé par la clé privée de "A") et ayant en pièce jointe le fichier contenant le message chiffré.
Si ce n'est pas déjà fait, "B" récupère la clé publique de "A" lui permettant de vérifier que la signature du message est bien authentique et que le contenu du message n'a pas été modifié.
Enfin, "B", à l'aide de sa clé privée, déchiffre le contenu de la pièce jointe.
Le processus est terminé.
Si le message de "A" a été intercepté par une personne malintentionnée "C", le contenu de la pièce jointe ne pourra pas être déchiffré sans la clé privée de "B". "C" ne pourra donc pas lire le contenu de la pièce jointe.
Ceci est un message chiffré.
-----BEGIN PGP MESSAGE-----
Version: GnuPG v2
hQEMAxetSMh+B9VxAQf/VvFi7T89Gn1gEfnsg1WTOW1uOJX9KgVnWF3QCxr87/zf
T0PCvJnEnt9HirAMu+nn9iMmnSju89RhIFjQkTVltLlfOJY7kQQBc1DdM7h2MYNI
632daM650f6LGa1ZQ3gbdc/pmdjq+YxrqJQM+lC36n3nSbuQjluJF2nv/R70sQXw
4pl2arebgqq45dRwNiGvOFsMpjyS1rLgQ9noA0p+N+OpiK/3YezRJGNl2SVspBqh
zDh/Qcweq2R66dtr8gsPhkeBy0/wy4bI2o6CC7oGEFC+RnKqkC3V4ZvfHhY3gjgu
pxlit6cKgoUfSXiMLWioKinWaqF4U+/YMyRnsLYAytJYAdI4rniMl89CbsQYhYCn
l7vTPBnUhLzHFQv/L+vcnxOPrRohVVfIm+zNyHv4QtSvtHc+/WTbhERE+cdCRvXP
l5oFR4/znpzU9XPknSjpRUZ3Ugy94bfe/Q==
=YUMp
-----END PGP MESSAGE-----
Certe, le message chiffré est un peu beaucoup plus long mais personne ne peut le lire mis à part celui pour lequel il a été chiffré.
La longueur du message chiffré n'est pas proportionnelle à la longueur du message clair.
Dans l'exemple ci-dessus, le message clair fait 29 caractères et le message chiffré 572 caractères.
Un autre test, avec un message clair de 116 caractères produit un message chiffré de 682 caractères.
Avec GPG, il est possible de chiffrer un message de trois manières différentes.
Pour un envoi directement dans le corp du mail, le mode ASCII est obligatoire
Pour un envoi en pièce jointe, c'est selon vos préférences ou la taille du fichier généré.
Pour pouvoir générer correctement les paires de clés (privée et publique), GPG a besoin d'une quantité importante de données aléatoires.
Pour générer ces données aléatoires, le système (Ubuntu/Debian/CentOS etc etc ...) a besoin d'une activité importante au niveau du processeur, de l'utilisation du ou des disques durs etc et c....
Pour faciliter la tâche, il existe un programme rng-tools, qui permet de faciliter la génération de données aléatoires sans solliciter le matériel.
# apt-get install rng-tools
# echo "HRNGDEVICE=/dev/urandom" >> /etc/default/rng-tools
# service rng-tools start
Il n'y a rien de plus à faire.
Désormais, tous les programmes, comme GPG, ayant un besoin important de données aléatoires auront leurs tâches facilitées par rng-tools.
On exécute la commande gpg --gen-key
# gpg --gen-key
gpg (GnuPG) 1.4.16; Copyright (C) 2013 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
gpg: directory `/root/.gnupg' created
gpg: new configuration file `/root/.gnupg/gpg.conf' created
gpg: WARNING: options in `/root/.gnupg/gpg.conf' are not yet active during this run
gpg: keyring `/root/.gnupg/secring.gpg' created
gpg: keyring `/root/.gnupg/pubring.gpg' created
Please select what kind of key you want:
(1) RSA and RSA (default)
(2) DSA and Elgamal
(3) DSA (sign only)
(4) RSA (sign only)
Your selection? 1
Lors du choix du type de clé, choisir (1) RSA and RSA (default)
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048)
Requested keysize is 2048 bits
Pour la longueur de la clé, laissé le choix par défaut 2048 bits.
Please specify how long the key should be valid.
0 = key does not expire
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years
Key is valid for? (0) 0
Key does not expire at all
Is this correct? (y/N) y
Pour la durée de validité de la clé, à vous de choisir.
Pour l'exemple je choisi 0 (La clé n'expire jamais)
Valider en répondant y pour YES
You need a user ID to identify your key; the software constructs the user ID
from the Real Name, Comment and Email Address in this form:
"Heinrich Heine (Der Dichter) <heinrichh@duesseldorf.de>"
Real name: Jean Michel A Peu Près
Email address: jm@apeupres.fr
Comment:
You selected this USER-ID:
"Jean Michel A Peu Près <jm@apeupres.fr>"
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o
Renseigner votre nom, votre adresse mail et un commentaire si vous le souhaitez.
Valider en répondant o pour OK
You need a Passphrase to protect your secret key.
Enter passphrase:
Repeat passphrase:
Renseigner une phrase de passe.
Surtout, ne la perdez pas.
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
GPG ayant besoin d'un grand nombre de données aléatoires pour pouvoir générer les clés, il est conseillé d'utiliser le poste un maximum pendant la génération des clés.
Utiliser au maximum le clavier, la souris etc etc.
gpg: /root/.gnupg/trustdb.gpg: trustdb created
gpg: key 0D6FE738 marked as ultimately trusted
public and secret key created and signed.
gpg: checking the trustdb
gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u
pub 2048R/0D6FE738 2015-09-11
Key fingerprint = C643 9D6C 9456 9961 58C1 CDC7 F700 1FBC 0D6F E738
uid Jean Michel A Peu Près <jm@apeupres.fr>
sub 2048R/1C51C149 2015-09-11
Une fois terminé, GPG nous informe que la clé privée et publique ont été créées et signées.
Le détail des clés est affiché à l'écran.
En fait, on s'aperçoit que la clé publique 0D6FE738 contient une sous-clé 1C51C149 (idem pour la clé privée).
Ce sont donc au total 4 clés qui ont été créées.
Une fois votre clé créée, vous pouvez indiquer dans votre fichier ~/.bashrc qu'il s'agit de votre clé par défaut en ajoutant la ligne:
# echo "export GPGKEY=0D6FE738" >> ~/.bashrc
# gpg --list-keys
/root/.gnupg/pubring.gpg
------------------------
pub 2048R/0D6FE738 2015-09-11
uid Jean Michel A Peu Près <jm@apeupres.fr>
sub 2048R/1C51C149 2015-09-11
pub 2048R/488606BD 2013-10-11 [expires: 2018-10-10]
uid Christopher lowson <webmin@lowson.ca>
uid Christopher Lowson <lowson.chris@gmail.com>
uid [jpeg image of size 2653]
sub 2048R/CA15AA23 2013-10-11 [expires: 2018-10-10]
pub 1024D/ACC3599B 2011-03-19
uid BT <bt@webmin.net>
sub 1024g/DA013131 2011-03-19
pub 1024D/A7F37C67 2009-04-17 [expired: 2010-07-31]
uid Max Ober <max.ober@gmail.com>
uid mober.at <post@mober.at>
uid mober.at <webmin@mober.at>
uid Max Ober <mober.itsb2006@fh-salzburg.ac.at>
uid n0942544@students.meduniwien.ac.at <n0942544@students.meduniwien.ac.at>
Ma clé publique 0D6FE738 apparait bien dans la liste ainsi que différentes clés importées 488606BD, ACC3599B, A7F37C67.
# gpg --list-keys Jean Michel A Peu Près
ou
# gpg --list-keys 0D6FE738
pub 2048R/0D6FE738 2015-09-11
uid Jean Michel A Peu Près <jm@apeupres.fr>
sub 2048R/1C51C149 2015-09-11
Nous voyons bien que notre clé publique 0D6FE738 contient une sous-clé 1C51C149
# gpg --list-secret-keys
/root/.gnupg/secring.gpg
------------------------
sec 2048R/0D6FE738 2015-09-11
uid Jean Michel A Peu Près <jm@apeupres.fr>
ssb 2048R/1C51C149 2015-09-11
Nous voyons également que notre clé privée 0D6FE738 contient, comme sa clé publique, une sous-clé 1C51C149
Nous allons éditer notre clé afin d'y apporter quelques modifications.
Cette commande nous permet d'entrer dans le mode interactif de GPG
# gpg --edit-key 0D6FE738
gpg (GnuPG) 1.4.16; Copyright (C) 2013 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Secret key is available.
pub 2048R/0D6FE738 created: 2015-09-11 expires: never usage: SC
trust: ultimate validity: ultimate
sub 2048R/1C51C149 created: 2015-09-11 expires: never usage: E
[ultimate] (1). Jean Michel A Peu Près <jm@apeupres.fr>
gpg>
Le mode édition nous permet de voir notre clé plus en détail.
Nous voyons, par exemple, que la clé privée est disponible (Secret key is available).
Nous voyons également, au niveau du champ usage, que notre clé maitresse 0D6FE738 peut-être utilisée pour certifier ou signer la clé publique d'un utilisateur (lettre C) et signer un document [mail / fichier] (lettre S).
Nous voyons que nous avons une sous-clé 1C51C149 qui va nous permettre de chiffrer un document [mail / fichier] (lettre E dans le champ usage).
Pour finir, nous voyons tous les détails concernant la date de création (created), la date d'expiration (expires) et le niveau de confiance (trust).
quit - Quitte le menu
save - Sauvegarde les modifications et quitte le menu
help - Affiche l'aide
fpr - Affiche l'empreinte de la clé sur 40 caractères
list - Affiche le détail de la clé
uid - Permet de sélectionner l'uid désiré
key - Permet de sélectionner la sous-clé désirée
check - Vérifie les signatures
sign - Signe l'uid sélectionné
adduid - Ajoute un uid
addphoto - Ajoute une photo
deluid - Supprime l'uid sélectionné
addkey - Ajoute une sous-clé
delkey - Supprime la sous clé sélectionnée
delsig - Supprime la signature de l'uid sélectionné
expire - Change la date d'expiration de la clé ou sous-clé sélectionnée
toggle - Bascule la liste clé publique / clé privée
passwd - Change la phrase de passe
trust - Modifie le niveau de confiance
revsig - Révoquer la signature de l'uid sélectionné
revuid - Révoquer l'uid sélectionné
revkey - Révoquer la clé ou sous-clé sélectionnée
enable - Active la clé
disable - Désactive la clé
Notre clé maitresse 0D6FE738 ayant deux usages (certification/signature de clé publique et signature de documents), nous allons ajouter une sous-clé qui nous permettra, uniquement, la signature de documents.
De la même manière que notre sous-clé 1C51C149 nous permet uniquement le chiffrement de documents.
gpg> addkey
Key is protected.
You need a passphrase to unlock the secret key for
user: "Jean Michel A Peu Près <jm@apeupres.fr>"
2048-bit RSA key, ID 0D6FE738, created 2015-09-11
Il faut obligatoirement saisir la phrase de passe
gpg: gpg-agent is not available in this session
Please select what kind of key you want:
(3) DSA (sign only)
(4) RSA (sign only)
(5) Elgamal (encrypt only)
(6) RSA (encrypt only)
Your selection? 4
Nous allons choisir l'option 4 qui nous permet de créer une sous-clé RSA uniquement pour la signature.
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048)
Requested keysize is 2048 bits
Nous laissons le choix par défaut pour la longueur de la clé (2048 bits)
Please specify how long the key should be valid.
0 = key does not expire
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years
Key is valid for? (0)
Key does not expire at all
Is this correct? (y/N) y
Choisir une date d'expiration
Je choisi le choix par défaut (n'expire jamais)
Really create? (y/N) y
Je confirme la création
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
pub 2048R/0D6FE738 created: 2015-09-11 expires: never usage: SC
trust: ultimate validity: ultimate
sub 2048R/1C51C149 created: 2015-09-11 expires: never usage: E
sub 2048R/219FE958 created: 2015-09-11 expires: never usage: S
[ultimate] (1). Jean Michel A Peu Près <jm@apeupres.fr>
gpg>
Et voilà, je me trouve en possession d'une paire de clé maitresse 0D6FE738 (privée/publique) pour la certification ou la signature de clé publique chacune ayant deux sous-clés, une pour le chiffrement de documents 1C51C149 (usage: E) et une pour la signature de documents 219FE958 (usage: S).
Une fois les modifications terminées, quitter le mode interactif en sauvegardant.
gpg> save
(A faire uniquement dans le cas où la ou les sous-clés sont compromises)
Il faut éditer la clé maitresse correspondante.
# gpg --edit-key 0D6FE738
gpg (GnuPG) 1.4.16; Copyright (C) 2013 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Secret key is available.
pub 2048R/0D6FE738 created: 2015-09-11 expires: never usage: SC
trust: ultimate validity: ultimate
sub 2048R/1C51C149 created: 2015-09-11 expires: never usage: E
[ultimate] (1). Jean Michel A Peu Près <jm@apeupres.fr>
gpg>
Sélectionner la sous-clé correspondante à l'aide de la commande key suivi du numéro d'index de la sous-clé.
Pour sélectionner la sous-clé 1 (index)
gpg> key 1
Même commande pour la désélectionner
gpg> key 1
L'index des clé/sous-clés commence à 0 (zéro).
Dans mon exemple, ma clé maitresse 0D6FE738 correspond à l'index 0, la sous-clé 1C51C149 à l'index 1 etc etc...
On sait qu'une sous-clé est sélectionnée quand un asterisk est présent sur la ligne (à coté de sub)
gpg> key 1
pub 2048R/0D6FE738 created: 2015-09-11 expires: never usage: SC
trust: ultimate validity: ultimate
sub* 2048R/1C51C149 created: 2015-09-11 expires: never usage: E
sub 2048R/219FE958 created: 2015-09-11 expires: never usage: S
[ultimate] (1). Jean Michel A Peu Près <jm@apeupres.fr>
Je sélectionne ma sous-clé 1C51C149 index 1 (un asterisk m'indique la clé sélectionnée)
gpg> revkey
Do you really want to revoke this subkey? (y/N) y
Please select the reason for the revocation:
0 = No reason specified
1 = Key has been compromised
2 = Key is superseded
3 = Key is no longer used
Q = Cancel
Your decision? 0
Enter an optional description; end it with an empty line:
>
Reason for revocation: No reason specified
J'exécute la commande revkey et je choisi l'option 0 (aucune raison spécifique)
Saisir une description optionnelle
(No description given)
Is this okay? (y/N) y
Valider
You need a passphrase to unlock the secret key for
user: "Jean Michel A Peu Près <jm@apeupres.fr>"
2048-bit RSA key, ID 0D6FE738, created 2015-09-11
Saisir la phrase de passe de la clé privée.
gpg: gpg-agent is not available in this session
pub 2048R/0D6FE738 created: 2015-09-11 expires: never usage: SC
trust: ultimate validity: ultimate
This key was revoked on 2015-09-11 by RSA key 0D6FE738 Jean Michel A Peu Près <jm@apeupres.fr>
sub 2048R/1C51C149 created: 2015-09-11 revoked: 2015-09-11 usage: E
sub 2048R/219FE958 created: 2015-09-11 expires: never usage: S
[ultimate] (1). Jean Michel A Peu Près <jm@apeupres.fr>
gpg>
L'indication revoked apparait bien sur la ligne de ma sous-clé.
Une fois les modifications terminées, quitter le mode interactif en sauvegardant.
gpg> save
Pour annuler les modifications
gpg> quit
Ne pas sauvegarder les modifications sinon vous allez révoquer la sous-clé et on ne pourra plus l'utiliser par la suite.
En effet, les clés et sous-clés ne doivent jamais être supprimées mais révoquées.
Cela permet de continuer à déchiffrer les anciens documents et vérifier les anciennes signatures.
La révocation se fait via le mode interactif et la commande revkey
Mais pour cela, il faut obligatoirement disposer de la paire de clé maitresse et de la phrase de passe.
En cas de perte de la clé maitresse ou la perte de la phrase de passe, il n'est plus possible de faire quoi que ce soit, il est donc impératif de créer le certificat de révocation de notre clé maitresse afin de la révoquer et pour pouvoir en créer une nouvelle. C'est une question de sécurité nationnale ;-)
# gpg --output revoke.asc --gen-revoke 0D6FE738
sec 2048R/0D6FE738 2015-09-11 Jean Michel A Peu Près <jm@apeupres.fr>
Create a revocation certificate for this key? (y/N) y
Please select the reason for the revocation:
0 = No reason specified
1 = Key has been compromised
2 = Key is superseded
3 = Key is no longer used
Q = Cancel
(Probably you want to select 1 here)
Your decision? 0
Choisir le motif de la révocation
Enter an optional description; end it with an empty line:
>
Saisir une description optionnelle
Reason for revocation: No reason specified
(No description given)
Is this okay? (y/N) y
Valider avec y pour YES
You need a passphrase to unlock the secret key for
user: "Jean Michel A Peu Près <jm@apeupres.fr>"
2048-bit RSA key, ID 0D6FE738, created 2015-09-11
Saisir la phrase de passe
gpg: gpg-agent is not available in this session
ASCII armored output forced.
Revocation certificate created.
Please move it to a medium which you can hide away; if Mallory gets
access to this certificate he can use it to make your key unusable.
It is smart to print this certificate and store it away, just in case
your media become unreadable. But have some caution: The print system of
your machine might store the data and make it available to others!
Ce certificat de révocation doit être stocké en lieu sûr et surtout pas avec la clé maitresse.
En cas de guerre nucléaire ;-) pour révoquer la clé maitresse:
# gpg --import revoke.asc
Aucune confirmation demandée. La clé maitresse est aussitôt révoquée.
# gpg --armor --export 0D6FE738 > clepub.asc
# gpg --armor --export-secret-keys 0D6FE738 > clesec.asc
# gpg --armor --export-secret-subkeys 0D6FE738 > subcle.asc
Seul le fichier clepub.asc contenant la clé publique peut être communiqué.
Pour éviter toute erreur de manipulation, sauvegarder également le dossier complet ~/.gnupg.
Enregistrer ces trois fichiers, ainsi que le fichier contenant la clé de révocation de la clé maitresse (revoke.asc) dans une archive TAR.
Chiffrer le fichier archive TAR avec la commande openssl (on est quand même jamais trop prudent)
# openssl enc -aes256 -in monFichier.tar -out monFichier.tar.aes256
Supprimer les 4 fichiers .asc ainsi que l'archive TAR. Le fichier clepub.asc peut-être conservé.
Conserver uniquement le fichier chiffré et l'enfermer à double tour dans un coffre fort sur Neptune.
Sans blague, il ne faut surtout pas le perdre.
Pourquoi supprimer (ou plutôt enlever) la clé privée maitresse de notre trousseau ?
Pour plus de sécurité.
Nous n'avons pas besoin de la clé privée maitresse pour signer et déchiffrer des documents.
Seules les sous-clés privées sont nécessaires.
Dans le cas où vous ne souhaitez pas faire d'autres opérations nécessitant la clé privée maitresse (signatures de clés publiques, ajout de sous-clés, révocation de sous-clés etc etc...), autant la supprimer du trousseau et la conserver à l'abris des regards indiscrets.
Attention, avant de procéder à la suppression de la clé privée du trousseau, sauvegarder toutes les clés dans des fichiers comme indiqué ici Exporter (sauvegarder) les clés dans des fichiers
On affiche nos clés privées.
# gpg --list-secret-keys
/root/.gnupg/secring.gpg
------------------------
sec 2048R/0D6FE738 2015-09-11
uid Jean Michel A Peu Près <jm@apeupres.fr>
ssb 2048R/1C51C149 2015-09-11
ssb 2048R/219FE958 2015-09-11
Nous avons bien dans notre trousseau un clé privée maitresse 0D6FE738 et deux sous-clés privées 1C51C149 & 219FE958.
On supprime notre clé privée maitresse.
# gpg --delete-secret-keys 0D6FE738
gpg (GnuPG) 1.4.16; Copyright (C) 2013 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
sec 2048R/0D6FE738 2015-09-11 Jean Michel A Peu Près <jm@apeupres.fr>
Delete this key from the keyring? (y/N) y
This is a secret key! - really delete? (y/N) y
On répond "y" aux deux questions.
On affiche à nouveau nos clés privées
# gpg --list-secret-keys
La commande ne retourne plus rien.
A ce stade, nous ne pouvons plus rien faire (ni signer, ni déchiffrer des documents) puisqu'en supprimant la clé privée maitresse, toutes les sous-clés privées ont été également supprimées.
Nous allons donc importer uniquement nos sous-clés privées (vous les avez normalement sauvegardées ;-).
# gpg --import subcle.asc
gpg: key 0D6FE738: secret key imported
gpg: key 0D6FE738: "Jean Michel A Peu Près <jm@apeupres.fr>" not changed
gpg: Total number processed: 1
gpg: unchanged: 1
gpg: secret keys read: 1
gpg: secret keys imported: 1
La commande nous indique que la clé privée a bien été importée.
On vérifie en affichant la liste des clés privées.
# gpg --list-secret-keys
/root/.gnupg/secring.gpg
------------------------
sec# 2048R/0D6FE738 2015-09-11
uid Jean Michel A Peu Près <jm@apeupres.fr>
ssb 2048R/1C51C149 2015-09-11
ssb 2048R/219FE958 2015-09-11
Le symbole dièse "#" à coté de "sec" nous indique que la clé privée maitresse est manquante mais que nous avons bien les deux sous-clés privées (ssb).
Si, pour une raison x vous avez besoin de réimporter dans votre trousseau votre clé privée maitresse, procéder de cette manière.
Ouvrer votre coffre-fort et récupérer la sauvegarde de vos clés (Elles sont censées être stockées dans un lieu sûr).
Supprimer les sous-clés privées.
# gpg --delete-secret-keys 0D6FE738
gpg (GnuPG) 1.4.16; Copyright (C) 2013 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
sec 2048R/0D6FE738 2015-09-10 Jean Michel A Peu Près <jm@apeupres.fr>
Delete this key from the keyring? (y/N) y
This is a secret key! - really delete? (y/N) y
Confirmer la suppression.
Vérifier la liste des clés privées.
# gpg --list-secret-keys
Notre trousseau ne contient plus de clés et sous-clés privées.
On importe notre clé privée maitresse (qui contient également les sous-clé privées).
# gpg --import clesec.asc
gpg: key 0D6FE738: secret key imported
gpg: key 0D6FE738: "Jean Michel A Peu Près <jm@apeupres.fr>" not changed
gpg: Total number processed: 1
gpg: unchanged: 1
gpg: secret keys read: 1
gpg: secret keys imported: 1
On affiche nos clés privées importées.
# gpg --list-secret-keys
/root/.gnupg/secring.gpg
------------------------
sec 2048R/0D6FE738 2015-09-11
uid Jean Michel A Peu Près <jm@apeupres.fr>
ssb 2048R/1C51C149 2015-09-11
ssb 2048R/219FE958 2015-09-11
Le symbole "#" à coté de "sec" a disparu.
Notre clé privée maitresse a bien été restaurée.
Plusieurs méthodes sont disponibles pour partager sa clé publique.
Pour la troisième méthode
# gpg --send-keys 0D6FE738
gpg: sending key CEA84BBA to hkp server keys.gnupg.net
Si vous avez sa clé publique dans un fichier
# gpg --import cle_publique_user_a.asc
En effectuant une recherche sur un serveur de clé
Par exemple, pour communiquer de manière chiffrée avec le président des Etats-Unis (trop la classe)
# gpg --fingerprint --search-keys Barack Obama
gpg: searching for "Barack Obama" from hkp server keys.gnupg.net
(1) Barack Obama <barack.obama@whitehouse.gov>
2048 bit RSA key CF4C3F70443ED0C5C3EE47555F31A132F752764E, created: 2015-01-02
(2) barack obama (hej) <hejhejhej@hotmail.com>
2048 bit RSA key FC54600AB3CB8A408005DCEE9001C823CB3D68F7, created: 2014-10-09
(3) Barack Hussein Obama <president@whitehouse.gov>
2048 bit RSA key 4AC1999F0BA293E8960AF2DA428C3085AF19CFE9, created: 2014-05-25, expires: 2018-05-25
(4) Barack Obama (Barack Obama) <xxgiricsxx@gmail.com>
1024 bit RSA key 03387652B395C4EC9DDA6AAFC9086C33FAE0BD4A, created: 2014-03-12
(5) Barack Hussein Obama (PoC) <presidente@casabranca.gov>
1024 bit RSA key 080C65142395677B22533461601F1B3201206B11, created: 2014-03-12 (revoked)
(6) Barack Obama (Si quieres pasar un buen rato llamma al timbre de la cas
3072 bit DSA key 06FE8A6A00EF1482C7AF545A06601E108440BE33, created: 2014-01-10, expires: 2014-01-11 (expired)
(7) Barack Obama <mmmyom@tormail.org>
2048 bit RSA key 09D7F58194D51A08F0DC8C6D0B998F9E9C8EFF37, created: 2013-05-28, expires: 2017-05-28
(8) Barack Obama (Pruba SAD) <shus_presi_EEUU@yopmail.com>
1024 bit RSA key 128F925760B14B1EBE7DFCD35F25557DE7D21FF0, created: 2012-10-10
(9) barack obama <bjjbb@ufl.edu>
2048 bit RSA key 099A86AA0E3383D0396A59E457435C9EE35A5D9F, created: 2011-11-10
(10) Barack Obama <baracko@whitehouse.com>
2048 bit RSA key 4E984FCDD33CC9F11B2E774FB9AA7F50D3EF826C, created: 2011-10-20
(11) Barack Hussein Obama (PoC) <presidente@casabranca.gov>
1024 bit DSA key DFC2235748027DE8897FF893A69404F176F5FE21, created: 2010-04-07, expires: 2010-04-14 (expired)
Keys 1-11 of 12 for "Barack Obama". Enter number(s), N)ext, or Q)uit >
Choisir la clé à importer.
L'option --fingerprint permet d'afficher l'empreinte de la clé et de la vérifier si celle-ci nous a été communiquée par le destinataire lui-même. Deux précautions valent mieux qu'une.
Je choisi d'importer la clé (1) - Je valide en appuyant sur Entrée
gpg: requesting key F752764E from hkp server keys.gnupg.net
gpg: key F752764E: public key "Barack Obama <barack.obama@whitehouse.gov>" imported
gpg: Total number processed: 1
gpg: imported: 1 (RSA: 1)
Quand on liste les clés
# gpg --list-keys
/root/.gnupg/pubring.gpg
------------------------
pub 2048R/0D6FE738 2015-09-11
uid Jean Michel A Peu Près <jm@apeupres.fr>
sub 2048R/1C51C149 2015-09-11
sub 2048R/219FE958 2015-09-11
...
pub 2048R/F752764E 2015-01-02
uid Barack Obama <barack.obama@whitehouse.gov>
sub 2048R/C4CDB034 2015-01-02
On voit que la clé F752764E a bien été importée.
Dorénavant, je suis en mesure d'envoyer des messages chiffrés au président des Etats-Unis Barack Obama (whaoo).
A ce stade, nous sommes en mesure de signer et chiffrer tous les documents que nous souhaitons.
Alors, suivez le guide ...
La signature d'un message exige la saisie de la phrase de passe de la clé privée à chaque fois.
"message" correspond à un fichier texte contenant le message à signer.
# cat message
Ceci est un message signé.
# gpg --sign message
Un nouveau fichier message.gpg est généré contenant le message et la signature au format binaire.
Pour lire le contenu du message, il faut obligatoirement utiliser gpg avec l'option --decrypt.
En effet, le message n'est pas chiffré, il est seulement signé, mais étant au format binaire, seule l'option --decrypt est capable de vérifier la signature et d'afficher le message en clair.
# gpg --clearsign message
Un nouveau fichier message.asc est généré contenant le message et la signature au format ASCII.
# gpg --detach-sign message
Un nouveau fichier message.sig est généré contenant uniquement la signature au format binaire.
# gpg --detach-sign --armor message
Un nouveau fichier message.asc est généré contenant uniquement la signature au format ASCII.
Pour modifier le nom du fichier généré, il faut utiliser l'option -o nomDuFichier (ou --output).
# gpg --detach-sign --armor -o signature.asc message
Il est possible de signer un message sans passer par l'intermédiare de fichiers (entrées/sorties)
# echo "Ceci est un message signé." | gpg --clearsign
You need a passphrase to unlock the secret key for
user: "Jean Michel A Peu Près <jm@apeupres.fr>"
2048-bit RSA key, ID 219FE958, created 2015-09-11 (main key ID 0D6FE738)
gpg: gpg-agent is not available in this session
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Ceci est un message signé.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1
iQEcBAEBAgAGBQJV9enkAAoJED/atMwhn+lYiz8H+wc1peA+zFNh0pI0Xl9LaCng
2BPlhod4MYO7yAJTKh76MHx1pXZAjPRZdvQf7WockS9gyHC2/h3MGcFMJZ4LAYdQ
16LfwCC2ip08FsiWuIjnAdC+qEcvLVM6MkH5iiKVgLRnwn7b7oqp9M/mwQGb8JmA
gxRwMTDZxxSBHjjIKPtbOzzN/Wp308WQiI1G0d/uM+GE8JmOQcGAz2pNS/i01KbR
7ft0RUGOtdlnZOyBpuTl90CEkEhFjICvoyB3EEoXAR+DorxhgRUGeGliZzgoKSeU
cWsGlMaigvofC67xSaWacIpk/GOv0hZUPMR9EqmKuCDqSHpcrnWX3W2JWYqwkZM=
=XBKV
-----END PGP SIGNATURE-----
Copier/coller le message signé dans un mail au format texte (tout le contenu de -----BEGIN PGP SIGNED MESSAGE----- jusqu'à -----END PGP SIGNATURE-----).
Pour envoyer la sortie vers un fichier, utiliser l'option -o monFichier (--output).
On signe le fichier message
# gpg --armor --detach-sign message
On vérifie la signature du fichier message.
L'option --verify prend en premier paramètre le nom du fichier contenant la signature (si la signature est dans un fichier à part) et le nom du fichier signé en second paramètre.
# gpg --verify message.asc message
gpg: Signature made Sun 13 Sep 2015 11:40:49 PM CEST using RSA key ID 219FE958
gpg: Good signature from "Jean Michel A Peu Près <jm@apeupres.fr>"
La signature est correcte.
On altère le fichier message pour simuler un piratage du fichier.
# echo "" >> message
On vérifie à nouveau la signature du fichier.
# gpg --verify message.asc message
gpg: Signature made Wed 16 Sep 2015 07:14:28 PM CEST using RSA key ID 219FE958
gpg: BAD signature from "Jean Michel A Peu Près <jm@apeupres.fr>"
Le résultat nous indique que la signature est incorrecte.
Nous avons la preuve que le fichier d'origine a été altéré.
Franchement, c'est quand même pas si compliqué de signer un fichier et c'est quand même plus sécurisant.
Et si maintenant on le chiffrait, ce fichier ...
Chiffrer un document n'est pas plus compliqué que de le signer.
Il faut juste avoir la clé publique du ou des destinataires du fichier. (ou avec sa propre clé publique si vous voulez seulement chiffrer des fichiers personnels)
Première question: A qui puis-je envoyer des messages/fichiers chiffrés ?
Pour le savoir, il faut lister toutes les clés publiques de notre trousseau.
# gpg --list-public-keys
/root/.gnupg/pubring.gpg
------------------------
pub 2048R/0D6FE738 2015-09-11
uid Jean Michel A Peu Près <jm@apeupres.fr>
sub 2048R/1C51C149 2015-09-11
sub 2048R/219FE958 2015-09-11
pub 2048R/F752764E 2015-01-02
uid Barack Obama <barack.obama@whitehouse.gov>
sub 2048R/C4CDB034 2015-01-02
Je vois que je peux chiffrer des documents pour moi-même et pour Barack Obama (oh la vache, j'avais oublié que j'avais importé sa clé publique).
Allez, c'est parti, envoyons un message chiffré à Barack.
# echo "Hello Barack, how are you ?" | gpg --encrypt --armor --recipient barack.obama@whitehouse.gov
gpg: checking the trustdb
gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
gpg: depth: 0 valid: 1 signed: 1 trust: 0-, 0q, 0n, 0m, 0f, 1u
gpg: depth: 1 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 1f, 0u
-----BEGIN PGP MESSAGE-----
Version: GnuPG v1
hQEMAxK9BLnEzbA0AQf8CLkg04MMJMxCrUiwHzcgaqL94gavPLBP/GIQP5bnxJFE
ujBziWFTwb9OxyKv6MWs9cegB1/qNKnYdgIWpDwjMWv+G/8wJfDqif002rEYPE+B
rRsnTXBQM+7QHXwATGpxudP85cY+WGp+cEb6PjkGvDzcBuTdlj2eQ8hm01TOKlpz
CDvbgZ58v4vz2W229fHDOD1sZ8WhYv5Q9+vX1mcTODC2terKtE+ekRrpfOjUE0Kf
U+tdUIqMrop63oWJmQgclejevfzmLGvhSaZPlZy8HlWUNfgPCxspJIu4+r89EJST
364F2n/cMig5f+o1dYWHRO+aY6OapatE/zxEul33G9JXAWqnqZQ8XsA9p3H0bGe3
vAFAAKvG3C0RUgvbwJaG2yzX5GYbunyek/f/B7LdugM+r+D8qo+3Ts61ZvjkunhO
kv34a7xaYuA4ckA3VZZgJ9/DQgoqBHO7
=QP5y
-----END PGP MESSAGE-----
Pour chiffrer un message, il suffit d'utiliser l'option --encrypt et l'option --recipient suivie de l'adresse mail du destinataire. (il est possible d'indiquer plusieurs fois l'option --recipient si il y a plusieurs destinataires)
Si vous n'avez pas signé la clé publique de chiffrement du destinataire, un message vous demandera si vous souhaitez vraiment utiliser la clé correspondante à l'adresse mail indiquée.
Pour signer une clé, il suffit de l'éditer gpg --edit-key xxxxxx, une fois dans le mode interactif de gpg, sélectionner la clé servant au chiffrement (drapeau E) avec la commande key suivi de l'index de la clé et la signer avec la commande sign. Tout est indiqué ici "Editer une clé".
Il reste à copier tout le contenu du message chiffré (de -----BEGIN PGP MESSAGE----- jusqu'à -----END PGP MESSAGE-----) et le coller dans un mail au format texte.
L'option -o (--output) peut être utilisée pour enregistrer le contenu du message chiffré dans un fichier.
Sans l'option --armor, le contenu sera chiffré au format binaire.
Pour chiffrer un fichier, il suffit d'indiquer son nom
# gpg --encrypt --armor --recipient barack.obama@whitehouse.gov message
Avec l'option --armor, un fichier .asc est généré (ASCII).
Sans l'option --armor, un fichier .gpg est généré (binaire).
En combinant les options de signatures, il est possible de signer et chiffrer un document.
# echo "Hello Barack, how are you ?" | gpg --sign --encrypt --armor --recipient barack.obama@whitehouse.gov
You need a passphrase to unlock the secret key for
user: "Jean Michel A Peu Près <jm@apeupres.fr>"
2048-bit RSA key, ID 219FE958, created 2015-09-11 (main key ID 0D6FE738)
gpg: gpg-agent is not available in this session
-----BEGIN PGP MESSAGE-----
Version: GnuPG v1
hQEMAxK9BLnEzbA0AQf8CFu2Jkc3wXtpg/H8eJ+jH5mf/pcm2NDUV17q8D7zohTf
sr7lsYW6IqWD5WtTd0hA/LVPHEl6UI4uXdzskNOdam+AJUUYqRDhXIos4mWof9Q/
e4hM1mz01tMSCIqmvIHvmYTRQOqu80wv2az7WJk7D7uxqVRfktA4dumVGwn3aIIc
RQ8chuHWIEUIteUJixsiYUIZj8jlQsvsZ9JMQmA3ugf3agOpNKcEwVyxhFhHw77q
oyogcVwfsI5mbKX6oZH93tsHG4gjUn/iiRXoWOsQuxzoqc7q90ndZHXRbQlsRZKw
qw4t9lsUg/NVsMGDDBxO4GpKgoQzoj27uqigV01q69LAyAFiR2YdUVtbqnNQ/HOJ
EcplnhCSmQNiHth5MY2yYFs9C7v1+HxItbUkufLIqv1qSHev6WmTaK9Ro+RkNVDQ
xwYwmyOZEcLpONRF6qWLkKk+PpctiSjSCd6lg7EvvEnPh9Lkz+n6fDgOIVCilKUX
IXn1l+JZX4e9Flan7KonyC7GEMJAUFedzxxVAKgcL0omFKqQq7iqRcBwXeTEZXd3
s1qYv1aQMN90sWfBamI3i9T8rtMyVABjEb+Mj1Qdp/vf+uNmuo14WZOyJT8zklnH
M+o+eG48dOSeg52FPUSw0L0BucqdXRu9llNWUiXYz2UnBe3KURMnpyMYrl7p2swm
AmAZTJ9zYfEAZkSzkArrdq2DcWYYW4CRtCLGojjxyDkN9AfZ79oDOl2qyy7xOlJ5
VY/HSX/gfMgYRKXR8do+fSW3cbm8u5j7cO2IdDzsahxZGdpPClFN3Mwjy6Zr59M+
tqlxKE+6Cyc1a44CeOUp6j2i01zqgDqG5Ru3CiPWTjk7GPP56/ELGdaz
=UKz1
-----END PGP MESSAGE-----
Ce message étant signé et chiffré, il est ultra sécurisé.
Difficle de faire mieux.
Vous avez un fichier contenant une multitude de "utilisateurs/mots de passe".
Chiffrer le avec GPG et supprimer le fichier d'origine.
Et quand vous avez besoin d'un mot de passe, déchiffrer le fichier avec l'option --decrypt et votre phrase de passe.
# cat motsdepasse
aaa fghdfkgjhdfgjkhdfgk
bbb mljfklsjgksjghskgjh
ccc sjhgjhkfgjkfhgjkfhg
# gpg --encrypt --recipient jm@apeupres.fr motsdepasse
# rm motsdepasse
# gpg --decrypt motsdepasse.gpg
You need a passphrase to unlock the secret key for
user: "Jean Michel A Peu Près <jm@apeupres.fr>"
2048-bit RSA key, ID 1C51C149, created 2015-09-11 (main key ID 0D6FE738)
gpg: gpg-agent is not available in this session
gpg: encrypted with 2048-bit RSA key, ID 1C51C149, created 2015-09-11
"Jean Michel A Peu Près <jm@apeupres.fr>"
aaa fghdfkgjhdfgjkhdfgk
bbb mljfklsjgksjghskgjh
ccc sjhgjhkfgjkfhgjkfhg
Vous remarquerez que le fichier est chiffré avec ma propre clé publique, et que pour le déchiffrer j'ai besoin de ma clé privée et de ma phrase de passe.
Quelques scripts pour bien utiliser Linux
Dans Linux, un script est un fichier rassemblant une succession de commandes.
Toutes les commandes peuvent être écrites les unes à la suite des autres.
Elles sont exécutées séquentiellement par le shell.
Pour une bonne exécution du script, il est toutefois conseillé de le structurer correctement pour éviter les mauvaises surprises.
Personnellement, je respecte toujours les règles suivantes :
1 - Toujours nommer son script avec l'extension ".sh" (facilite la recherche)
2 - La première ligne d'un script doit toujours indiquer quel interpréteur de commande utiliser, par exemple :
#!/bin/bash
#!/bin/sh
#!/usr/bin/python
#!/usr/bin/php
3 - Renseigner la variable PATH :
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
La variable PATH permet d'indiquer au shell les répertoires où sont situés les commandes externes utilisées.
En console, la variable PATH est initialisée à la connexion ce qui fait qu'il n'est pas nécessaire d'indiquer le chemin complet d'une commande afin de l'exécuter. Si le script est exécuté uniquement en console, il n'est pas nécessaire d'initialiser la variable PATH mais si le script est exécuté via une tâche cron, la variable PATH est inconnue, dans ce cas, toutes les commandes externes utilisées dans le script ne pourront pas être exécutées.
4 - Rediriger la sortie d'erreur standard dans un fichier de log spécifique, par exemple :
exec 2>>/var/log/mon_script_error.log
exec 2>/dev/null (s'il n'est pas nécessaire de "logguer" les différentes erreurs rencontrées)
5 - Terminer le script avec la commande suivante :
exit 0
Exemple avec un script basique :
$ cat mon_script.sh
#!/bin/bash
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
exec 2>/dev/null
...
mes commandes
...
exit 0
Pour effectuer une sauvegarde différentielle, il faut utiliser le programme rdiff-backup.
Pour l'installer :
$ sudo apt-get install rdiff-backup
Pour créer une sauvegarde différentielle :
Créer un fichier, par exemple sauvegarde_differentielle.sh et y inscrire les deux lignes suivantes
$ cat sauvegarde_differentielle.sh
#!/bin/sh
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
exec 1>>/var/log/sauvegarde_differentielle.log
exec 2>>/var/log/sauvegarde_differentielle_error.log
nice -n 19 rdiff-backup /repertoire_a_sauvegarder /destination_de_la_sauvegarde && nice -n 19 rdiff-backup --remove-older-than 1W --force /destination_de_la_sauvegarde
exit 0
$
Voir également cette rubrique pour plus de renseignements
Ecrire dans le fichier la ligne suivante
$ cat maj.sh
#!/bin/sh
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
sudo apt-get update && sudo apt-get upgrade
exit 0
Pour exécuter ce script, taper dans la console
$ $MAJ
Une autre méthode, plus simple, consiste à créer un alias dans le fichier ~/.bashrc.
$ echo "alias maj='sudo apt-get update && sudo apt-get upgrade'" >> ~/.bashrc
Prendre en compte le nouvel alias créé :
$ . ~/.bashrc
Pour l'exécution :
$ maj
Pour surveiller un processus et le redémarrer en cas de plantage, créer une tâche cron exécutée en tant que root avec la commande suivante :
Par exemple, pour le processus DOVECOT (serveur POP / IMAP)
$ pgrep dovecot > /dev/null || { /etc/init.d/dovecot restart ; }
$ cat sauvegarde.sh
#!/bin/bash
####### sauvegarde - Sauvegarde le sources.list et les paquets #######
echo
echo "Script de sauvegarde APT'"
echo
DATE=`date +%F`
if test -d $DATE
then echo "Le dossier \"$DATE\" existe déjà. Voulez-vous refaire la sauvegarde ? [o/n]"
read choix
if [ $choix = "n" ]
then
echo
echo "Abandon."
exit 0
elif [ $choix = "o" ]
then
echo
echo "Réécriture de la sauvegarde $DATE..."
else
echo "Veuillez taper \"o\" ou \"n\"."
exit 2
fi
else
mkdir $DATE
fi
( cp /etc/apt/sources.list ./$DATE/sources.$DATE.list && dpkg --get-selections > ./$DATE/paquets.$DATE.list ) \
&& echo "Sauvegarde terminée dans $PWD/$DATE" \
|| echo "Sauvegarde échouée..."
exit 0
$ cat restauration.sh
#!/bin/bash
####### restauration - Script de restauration APT #######
echo
echo "Script de restauration APT"
echo "Une connexion Internet fonctionnelle est requise pour le bon fonctionnement de ce script."
echo
##### DEBUT GESTION DES ERREURS #####
ls -1 | grep '^[[:digit:]]\{4\}\-[[:digit:]]\{2\}\-[[:digit:]]\{2\}$' > /dev/null
if test $? -ne 0
then
echo "Il n'y a rien à restaurer !"
exit 2
elif [ ! `whoami` = "root" ]
then
echo "Il faut être root ... Executez \"sudo !!\"."
exit 2
elif test $# -ne 1
then
echo "Il faut un seul paramètre. Tapez \"./restauration sources\" pour restaurer le sources.list ou \"./restauration paquets\" pour restaurer les paquets."
exit 2
fi
##### FIN GESTION DES ERREURS #####
##### DEBUT SELECTION D'UNE DATE #####
echo
echo "Par défaut le script restaure votre sauvegarde la plus récente. Voulez-vous en restaurer une autre ? [o/n]"
read choix
if [ $choix = "n" ] # Si il veut la plus récente, on prend la plus récente en fonction du nom des dossiers de sauvegarde
then
DATE=`ls -1 | grep '^[[:digit:]]\{4\}\-[[:digit:]]\{2\}\-[[:digit:]]\{2\}$' | tail -n 1`
echo "La date choisie est $DATE."
elif [ $choix = "o" ] # Sinon on lui demande de rentrer une date
then
echo "Veuillez entrer la date souhaitée, sous la forme AAAA-MM-JJ : "
read DATE
if test -d $DATE
then
echo "La date choisie est $DATE."
else
echo "La date demandée n'existe pas dans les sauvegardes !"
exit 2
fi
else
echo "Veuillez entrer \"o\" ou \"n\"."
exit 2
fi
echo
echo "Est-ce bien ce que vous voulez ? [o/n]" # Confirmation
read choix2
if [ $choix2 = "o" ]
then
echo "Continuons donc !"
sleep 2 # On dort 2 secondes pour la lisiblité
elif [ $choix2 = "n" ]
then
echo "Abandon."
exit 2
else
echo "Veuillez entrer \"o\" ou \"n\"."
exit 2
fi
echo
##### FIN SELECTION D'UNE DATE #####
##### DEBUT RESTAURATION #####
if test $1 = "sources" # Si on veut restaurer le sources.list
then
cp /etc/apt/sources.list /etc/apt/sources.list.svgorig.$DATE
( cp $DATE/sources.$DATE.list /etc/apt/sources.list && apt-get update ) \
&& (echo ; echo "Restauration du sources.list terminée avec succès.") \
|| (echo ; echo "Restauration du sources.list échouée... Vous n'avez probablement pas les droits d'écriture dans /etc/apt/" ; \
cp /etc/apt.sources.list.svgorig.$DATE /etc/apt/sources.list && echo "Votre sources.list original a été restauré." ; exit 2)
elif test $1 = "paquets" # Si on veut restaurer les paquets
then
( dpkg --set-selections < $DATE/paquets.$DATE.list && apt-get update ; apt-get dselect-upgrade ) \
&& (echo ; echo "Restauration des paquets terminée avec succès") \
|| (echo ; echo "Restauration des paquets échouée... Votre connexion Internet est peut-être défaillante." ; exit 2)
else
echo "Paramètre inconnu"
exit 2
fi
exit 0
##### FIN RESTAURATION #####
Détail du script
$ nl explode.sh
1 #!/bin/bash
2 chemin="chemin 1|chemin 2 chemin 2 et demi|chemin 3"
3 #Sauvegarde de la valeur du IFS
4 #La variable $IFS doit être obligatoirement entre guillemets
5 old="$IFS"
6 #Modification de la valeur du IFS avec le "|"
7 IFS="|"
8 #Creation du tableau
9 tab=( $chemin )
10 #Restauration de la valeur du IFS
11 #La variable $old doit être obligatoirement entre guillemets
12 IFS="$old"
13 #Parcourt du tableau
14 for (( i=0 ; i<${#tab[*]} ; i++ )) ; do
15 echo $i" -> "${tab[$i]}
16 done
17 exit 0
$
Résultat :
$ ./explode.sh
0 -> chemin 1
1 -> chemin 2 chemin 2 et demi
2 -> chemin 3
$
Le script suivant permet d'afficher, par caractères, le nombre de fois qu'il est utilisé.
$ cat compteCaracteres.awk
BEGIN {
RS = "\n"
}
{
split($0, tab, "")
for (var in tab) {
tab2[tab[var]]+=1
}
}
END {
for (var in tab2) {
printf "%1s --> %6d\n" , var , tab2[var]
}
exit 0
}
Exemple :
$ echo "ceci est un test" | awk -f compteCaracteres.awk
u --> 1
i --> 1
n --> 1
--> 3
c --> 2
e --> 3
s --> 2
t --> 3
On peut également effectuer un tri sur le résultat :
$ echo "ceci est un test" | awk -f compteCaracteres.awk | sort
--> 3
c --> 2
e --> 3
i --> 1
n --> 1
s --> 2
t --> 3
u --> 1
En utilisant un fichier en entrée :
$ cat file
TARGUANT
LOGOS
SOCRATISERONS
TEMPORISERENT
PLASTIQUAIENT
CORROBORER
BOTTELES
LIGOTA
SATINERONT
HYPNOTISERA
Affichage du résultat avec un tri décroissant sur le nombre de fois que le caractère est utilisé
$ cat file | awk -f compteCaracteres.awk | sort -b -n -k 3 -r
T --> 13
O --> 12
R --> 11
E --> 10
S --> 9
A --> 8
N --> 7
I --> 7
L --> 4
P --> 3
G --> 3
U --> 2
C --> 2
B --> 2
Y --> 1
Q --> 1
M --> 1
H --> 1
Voici un script qui permet d'afficher les adresses IP (v4) de toutes les interfaces réseau installées sur la machine.
Exécution :
$ ./getInetAddr.sh
eth0 ==> 10.33.43.10
lo ==> 127.0.0.1
wlan0 ==> 172.22.8.35
Ce script est disponible en téléchargement ici .
Egalement disponible via GIT :
$ git clone http://git.quennec.fr/ronan/scripts_pub.git
Détail du script commenté :
Voici un script qui permet de trouver les anagrammes d'un mot ou d'une suite de lettres.
Ce script utilise un dictionnaire de plus de 336500 mots.
Ce dictionnaire de mots peut être téléchargé ICI.
Il est également disponible ICI au format UTF-8.
Ce script s'utilise de cette manière :
$ anagramme.sh -f fichierDictionnaire [-d] -l nbLettre -c listeLettres
L'option -f permet d'indiquer le fichier "dictionnaire" à utiliser.
L'option -l permet d'indiquer le nombre de lettres des anagrammes à rechercher.
L'option -c permet d'indiquer le mot ou les lettres des anagrammes à rechercher.
L'option -d permet de ne pas prendre en compte les caractères accentués.
Cliquez ICI pour télécharger le script ou via mon GitLab.
Exécution du script :
# ./scripts/anagramme.sh -f liste.de.mots.francais.frgut.txt.utf8 -l 6 -c aspire
Liste des mots de 6 lettre(s) et contenant les lettres "aspire" :
1 - aspire
2 - paires
3 - paries
4 - parsie
5 - repais
# ./scripts/anagramme.sh -f liste.de.mots.francais.frgut.txt.utf8 -l 8 -c fuaaieujoslw
Liste des mots de 8 lettre(s) et contenant les lettres "fuaaieujoslw" :
1 - jalousai
2 - jalousie
Avec l'option -d :
# ./scripts/anagramme.sh -f liste.de.mots.francais.frgut.txt.utf8 -d -l 6 -c aspire
Liste des mots de 6 lettre(s) et contenant les lettres "aspire" :
1 - aspire
2 - aspire
3 - epairs
4 - paires
5 - paries
6 - paries
7 - parsie
8 - repais
Ci-dessous le détail du script avec un maximum de commentaires :
# nl scripts/anagramme.sh
1 #!/bin/bash
2 # Activation du debug
3 # Décommenter pour activer
4 #set -x
5 # Fonction permettant de tester l'existence des commandes passées en argument
6 function preRequis {
7 for arg in $@; do
8 if ! which $arg >/dev/null; then
9 logger -t $0 "La commande $arg n'est pas installée"
10 echo "La commande $arg n'est pas installée !!!"
11 echo "Fin du script."
12 exit 1
13 fi
14 done
15 }
16 # Journalisation de l'exécution du script
17 logger -t $0 "Exécution du script"
18 # Initialisation de la variable PATH
19 PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games"
20 # Exécution de la fonction preRequis
21 preRequis grep sed awk
22 # Vérification du nombre d'arguments passés au script
23 #if [[ ! $# -eq 6 ]]; then
24 if [[ $# -lt 6 || $# -gt 7 ]]; then
25 echo "Nombre d'arguments incorrect"
26 echo "Utilisation : $0 -f fichierDictionnaire [-d] -l nbLettre -c listeLettres"
27 exit 1
28 fi
29 # Suppression des caractères accentués (0 = NON / 1 = OUI)
30 supprAccents=0
31 # Validation des arguments passés au script
32 while getopts ":f:c:l:d" option; do
33 case $option in
34 f)
35 if [ -f "$OPTARG" ]; then
36 LISTE="$OPTARG"
37 else
38 echo "L'option -f requiert un fichier existant."
39 exit 1
40 fi
41 ;;
42 c)
43 listeDesLettres="$OPTARG"
44 if ! grep -E -q -i "^[a-z]*$" <<< "$listeDesLettres"; then
45 echo "L'option -c requiert les lettres [a-z]."
46 exit 1
47 fi
48 ;;
49 l)
50 nbLettre="$OPTARG"
51 if ! grep -E -q "^[0-9]*$" <<< "$nbLettre"; then
52 echo "L'option -l requiert une valeur numérique."
53 exit 1
54 fi
55 ;;
56 d)
57 supprAccents=1
58 ;;
59 :)
60 echo "L'option $OPTARG requiert un argument."
61 exit 1
62 ;;
63 \?)
64 echo "$OPTARG : option invalide."
65 exit 1
66 ;;
67 esac
68 done
69 # Initialisation des variables utilisées pour le script
70 listeDesLettres2="$listeDesLettres"
71 listeDesMots2=""
72 ind=1
73 # Réécriture de la liste des lettres en incluant un pipe entre chaque lettre pour l'utiliser avec la commande grep
74 # abcdef -> a|b|c|d|e|f|
75 listeDesLettres=$(sed -r 's/([a-zA-Z])/\1\|/g' <<< "$listeDesLettres")
76 # Recherche tous les mots contenant le nombre et les lettres indiqués
77 if [[ $supprAccents = "0" ]]; then
78 listeDesMots=$(cat "$LISTE" | grep -E -e "^.{$nbLettre}$" | grep -E -i "^[$listeDesLettres]+$")
79 else
80 listeDesMots=$(cat "$LISTE" | sed 'y/àâäéèêëîïôöùûüç/aaaeeeeiioouuuc/' | grep -E -e "^.{$nbLettre}$" | grep -E -i "^[$listeDesLettres]+$")
81 fi
82 # On parcourt tous les mots trouvés par la commande précédente.
83 # Chaque mot et la liste des lettres sont passés à la commande AWK.
84 # AWK initialise un tableau avec la liste des lettres (avec la commande split).
85 # Chaque lettre est remplacée dans le mot par un blanc avec la commande sub ...
86 # ... et le résultat renvoyé par la commande (1 en cas de succès et 0 en cas d'échec) ...
87 # ... est multiplié à la variable "a". Pour finir, la commande AWK retourne le résultat de la variable "a".
88 # Si la commande AWK retourne "1" (signifiant une erreur en BASH - D'où le "!" après le "if" )
89 # c'est que toutes les lettres du mot correspondent à la liste des lettres à chercher.
90 # On sauvegarde donc le mot en cours dans la variable "listeDesMots2".
91 while read mot; do
92 if ! echo "$mot|$listeDesLettres2" | awk -F'|' 'BEGIN{a=1;b=1}{split($1,tab,"");for(var in tab){b=sub(tab[var],"",$2);a*=b}}END{exit a}'; then
93 listeDesMots2="$listeDesMots2\n$ind - $mot"
94 ind=$(expr $ind + 1)
95 fi
96 done <<< "$listeDesMots"
97 # Affichage de la liste des mots trouvés
98 echo -n "Liste des mots de $nbLettre lettre(s) et contenant les lettres \"$listeDesLettres2\" :"
99 echo -e "$listeDesMots2"
100 # Journalisation de la fin du script
101 logger -t $0 "Fin d'exécution du script"
102 # Fin du script
103 exit 0
Voici un script qui permet de calculer le PGCD et le PPCM d'au moins deux nombres.
Il s'utilise de cette manière :
$ ./pgcd.sh 50 68 54 etc etc ...
Voici le contenu du script :
$ nl scripts/pgcd.sh
Tous les détails de la commande mcrypt
La commande mcrypt propose différentes solutions afin de l'utiliser via un script.
Soit en utilisant un fichier de configuration, soit en utilisant des variables d'environnement.
Il est possible d'utiliser un fichier de configuration qui sera utilisé par défaut par la commande mcrypt.
Ce fichier doit être obligatoirement nommé ".mcryptrc" et placé dans le home de l'utilisateur.
Il devra contenir 3 paramètres :
- l'algorithme à utiliser
- le mode d'encryptage
- la phrase de passe
$ ls -l .mcryptrc
-rw------- 1 root root 46 31 oct. 09:09 .mcryptrc
$ cat .mcryptrc
algorithm des
mode cbc
key ma_phrase_de_passe
$
Lors de l'utilisation de la commande mcrypt, les paramètres d'encryptage seront automatiquement récupérés.
$ mcrypt monFichier
Warning: It is insecure to specify keywords in the command line
File monFichier was encrypted.
$ ls -l monFichier*
-rw-r--r-- 1 root root 0 31 oct. 08:32 monFichier
-rw------- 1 root root 84 31 oct. 08:32 monFichier.nc
$
Il est également possible d'utiliser un fichier de configuration nommé différemment mais dans ce cas, il faudra le spécifier lors de l'utilisation de la commande mcrypt avec l'option -c.
$ ls -l my_config_file
-rw------- 1 root root 46 31 oct. 09:15 my_config_file
$ cat my_config_file
algorithm des
mode cbc
key ma_phrase_de_passe
$ mcrypt -c my_config_file monFichier
Warning: It is insecure to specify keywords in the command line
File monFichier was encrypted.
$ ls -l monFichier*
-rw-r--r-- 1 root root 0 31 oct. 08:32 monFichier
-rw------- 1 root root 84 31 oct. 08:32 monFichier.nc
$
Il est possible égalment d'utiliser des variables d'environnement qu'il faudra initialiser et exporter directement dans le script utilisant la commande mcrypt.
Ces variables sont :
MCRYPT_KEY:la phrase de passe
MCRYPT_ALGO:l'algorithme à utiliser
MCRYPT_MODE:le mode d'encryptage
Exemple d'un script :
$ cat mon_script.sh
#!/bin/bash
export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
export MCRYPT_KEY="la phrase de passe"
export MCRYPT_ALGO="DES"
export MCRYPT_MODE="CBC"
if [[ -e monFichier.nc ]]; then
rm monFichier.nc
fi
mcrypt monFichier
exit 0
$
Dans ce script, les variables propres à mcrypt sont initialisées et exportées.
Un test sur l'existence du fichier crypté permet de le supprimer avant d'exécuter la commande mcrypt (cela évite d'avoir un message de confirmation de la commande mcrypt pour écraser le fichier)
Enfin, la commande mcrypt est exécutée sur le fichier "monFichier".
Exécution du script :
$ ./mon_script.sh
File monFichier was encrypted.
$
Ce script peut être utilisé pour envoyer un fichier sur un serveur FTP par exemple sans compromettre les données du fichier.
Pré-requis : Installer les paquets suivants
$ apt-get install ffmpeg
$ apt-get install ubuntu-restricted-extras
$ apt-get install lame
Exécuter le script suivant :
$ cat convert.sh
#!/bin/bash
for i in *.ogg
do
j=${i%.ogg} ffmpeg -ab 192k -i "$j.ogg" "$j.mp3"
done
exit 0
Convertit tous les fichiers présents dans le dossier où le script est exécuté
Voici un script qui permet de découper un ou plusieurs mots en syllabes.
Merci à http://www.bertrandboutin.ca/Folder_151_Grammaire/P_b_division.htm pour la définition des syllabes.
Ce script peut être téléchargé ICI. ou via mon GitLab
Il s'utilise de cette manière :
$ ./syllabes.sh mot1 mot2 mot3 mot4 etc etc ...
Le script accepte au minimum un mot.
Voici le détail du script avec un maximum de commentaires :
$ cat syllabes.sh
#!/bin/bash
# Activer pour le debug
#set -x
function preRequis {
for arg in $@; do
if ! which $arg >/dev/null; then
echo "La commande $arg n'est pas installée !!!"
echo "Fin du script."
exit 1
fi
done
}
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games"
preRequis egrep sed
# Si le nombre d'arguments passé au script est inférieur à 1
# On quitte le script immédiatement.
if [ $# -lt 1 ]; then
echo "Usage: `basename $0` mot1 [mot2 mot3 ...]"
exit 1
fi
# Liste des voyelles
VOY="aeiouyàâäéèêëîïôöùûü"
# Liste des consonnes
CONS="zrtpqsdfghjklmwxcvbnç"
# Liste des groupes de lettres insécables
GR="bl cl fl gl pl br cr dr fr gr pr tr vr ch ph gn th"
for MOT in $@; do
# On convertit toutes les majuscules en minuscules
_MOT=$(tr "[A-Z]" "[a-z]" <<< "$MOT")
# On exécute la première règle de découpe des syllabes
# avec les groupes de lettres insécables.
for _GR in $(echo $GR); do
_MOT=$(sed "s/$_GR/-$_GR/g" <<< "$_MOT")
done
# Boucle infinie
while :; do
# Une consonne placée entre deux voyelles introduit une nouvelle syllabe.
if SYL=$(grep -E -o "[$VOY]{1}[$CONS]{1}[$VOY]{1}" <<< "$_MOT"); then
for __SYL in $SYL; do
_SYL=$(sed -r "s/^(.)(.{2})$/\1-\2/" <<< "$__SYL")
_MOT=$(sed "s/$__SYL/$_SYL/" <<< "$_MOT")
done
continue
fi
# Deux consonnes placées entre deux voyelles,
# la première appartient à la syllabe précédente,
# la seconde, à la syllabe suivante.
if SYL=$(grep -E -o "[$VOY]{1}[$CONS]{2}[$VOY]{1}" <<< "$_MOT"); then
for __SYL in $SYL; do
_SYL=$(sed -r "s/^(.{2})(.{2})$/\1-\2/" <<< "$__SYL")
_MOT=$(sed "s/$__SYL/$_SYL/" <<< "$_MOT")
done
continue
fi
# Quand il y a trois consonnes ou voyelles consécutives à l’intérieur d’un mot,
# ordinairement les deux premières terminent une syllabe,
# l’autre commence une nouvelle syllabe.
if SYL=$(grep -E -o "[$CONS]{3}|[$VOY]{3}" <<< "$_MOT"); then
for __SYL in $SYL; do
_SYL=$(sed -r "s/^(.{2})(.)$/\1-\2/" <<< "$__SYL")
_MOT=$(sed "s/$__SYL/$_SYL/" <<< "$_MOT")
done
continue
fi
# On quitte la boucle infinie si aucune des conditions précédentes n'est vraie
break
done
# On affiche le résultat
_MOT=$(sed "s/^-//" <<< "$_MOT")
echo -e "$MOT => $_MOT"
done
exit 0
Enregistrer les erreurs d'exécution d'une commande ou d'un script dans un fichier de log peut se faire tout simplement en redirigeant la sortie d'erreur standard (descripteur #2) vers un fichier :
$ cp fichierA fichierB 2>>/var/log/cp_error.log
Petit rappel :
2>/mon_fichier : Tout le contenu du fichier est écrasé
2>>/mon_fichier : Les données sont ajoutées à la fin du fichier
La consultation du fichier log :
$ cat /var/log/cp_error.log
cp: impossible d'évaluer « fichierA »: Aucun fichier ou dossier de ce type
$
C'est clair et précis. L'erreur rencontrée par la commande cp a bien été enregistrée dans le fichier.
Mais la précision pourrait être un peu plus détaillée surtout si cela concerne une commande ou un script exécuté régulièrement par une tâche cron.
Le but, obtenir un fichier de log avec la date et l'heure de l'erreur rencontrée :
$ cat /var/log/cp_error.log
ven. 24 août 2012 15:10:01 CEST --- cp: impossible d'évaluer « fichierA »: Aucun fichier ou dossier de ce type
ven. 24 août 2012 15:12:07 CEST --- cp: impossible d'évaluer « fichier1 »: Aucun fichier ou dossier de ce type
ven. 24 août 2012 15:12:07 CEST --- cp: impossible d'évaluer « fichier2 »: Aucun fichier ou dossier de ce type
ven. 24 août 2012 15:12:07 CEST --- cp: impossible d'évaluer « fichier3 »: Aucun fichier ou dossier de ce type
ven. 24 août 2012 15:12:07 CEST --- cp: impossible d'évaluer « fichier4 »: Aucun fichier ou dossier de ce type
ven. 24 août 2012 15:12:07 CEST --- cp: impossible d'évaluer « fichier5 »: Aucun fichier ou dossier de ce type
ven. 24 août 2012 15:12:07 CEST --- cp: impossible d'évaluer « fichier6 »: Aucun fichier ou dossier de ce type
ven. 24 août 2012 15:12:07 CEST --- cp: impossible d'évaluer « fichier7 »: Aucun fichier ou dossier de ce type
ven. 24 août 2012 15:12:07 CEST --- cp: impossible d'évaluer « fichier8 »: Aucun fichier ou dossier de ce type
ven. 24 août 2012 15:12:07 CEST --- cp: impossible d'évaluer « fichier9 »: Aucun fichier ou dossier de ce type
ven. 24 août 2012 15:12:07 CEST --- cp: impossible d'évaluer « fichier10 »: Aucun fichier ou dossier de ce type
$
C'est quand même mieux de connaitre la date et l'heure de l'erreur rencontrée.
La manière de le faire ? Avec un simple script awk.
Pré-requis :
Avoir gawk installé sur la machine.
$ dpkg -l | grep -i awk
ii gawk 1:3.1.7.dfsg-5 GNU awk, a pattern scanning and processing language
ii mawk 1.3.3-15 a pattern scanning and text processing language
$
S'il n'est pas installé :
$ apt-get install gawk
Détail du script awk :
$ cat log.awk
{
date_heure=strftime("%c",systime())
printf ("%s --- %s\n", date_heure, $0)
}
END {
exit 0
}
$
Que fait-il :
Ce script reçoit une donnée en entrée récupérée grâce à la variable $0, initialise une variable date_heure avec la date et l'heure courante grâce à la commande systime() et formatée grâce à la commande strftime puis envoi le tout sur sa sortie standard grâce à la fonction printf.
Comment l'utiliser :
Avec une commande shell :
$ cp fichierA fichierB 2>&1 >&- | /usr/bin/awk -f /root/log.awk >> /var/log/cp_error.log
La commande cp tente de copier le fichierA vers le fichierB.
La sortie d'erreur standard de la commande cp est renvoyée en premier vers la sortie standard.
La sortie standard est ensuite fermée ce qui fait que seules les erreurs sont envoyées sur la sortie standard de la commande.
La sortie standard de la commande cp est ensuite envoyée au script log.awk.
Enfin, la sortie standard du script log.awk est envoyée vers le fichier de log souhaité.
L'utilisation avec un script est aussi possible :
$ /root/mon_script.sh 2>&1 >&- | /usr/bin/awk -f /root/log.awk >> /var/log/mon_fichier.log
Si l'on souhaite envoyer la totalité des résultats d'une commande ou d'un script dans le fichier de log, il suffit de supprimer la fermeture du descripteur #1.
$ cp fichierA fichierB 2>&1 | /usr/bin/awk -f /root/log.awk >> /var/log/cp_error.log
Il n'est pas rare d'avoir sur son disque dur le même fichier présent à plusieurs endroits.
Comme des photos, par exemple ou des programmes.
Que de place perdue pour pas grand chose.
Voici un petit script qui scrute le répertoire, passé en argument, à la recherche de fichiers en double (voir plus).
Comme dans la plupart de mes scripts, vous y retrouverez la fonction "preRequis" permettant de savoir si toutes les commandes utilisées dans le script sont biens installées sur le système et la commande logger permettant de journaliser l'exécution du script dans /var/log/syslog.
Téléchargé le script ici.
Le script s'utilise de cette manière :
$ ./rechercheDoublons.sh mon_repertoire
J'utilise la commande find avec l'option -type f qui permet de rechercher tous les fichiers réguliers dans le répertoire passé en argument.
Pour chaque fichier retourné par la commande find, la commande md5sum lit le fichier en mode binaire (avec l'option -b) et écrit l'empreinte md5 du fichier dans le fichier /tmp/filesMd5sum.
Pour finir, le contenu du fichier /tmp/filesMd5sum est trié avec la commande sort, et tous les fichiers ayant la même empreinte md5 (grâce aux commandes awk '{print $1}' | uniq -d) sont affichés à l'écran.
# cat rechercheDoublons.sh
#!/bin/bash
function preRequis {
for arg in $@; do
if ! which $arg >/dev/null; then
logger -t $0 La commande $arg n\'est pas installée
echo "La commande $arg n'est pas installée !!!"
echo "Fin du script."
exit 1
fi
done
}
logger -t $0 Exécution du script
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games"
preRequis md5sum sort awk uniq grep cut find
if [ ! $# -eq 1 ]; then
echo "Erreur !!!"
echo "Utilisation : $0 répertoire"
exit 1
fi
FILE="/tmp/filesMd5sum"
REP="$1"
if [ ! -d "$REP" ]; then
echo "Erreur !!!"
echo "$REP n'est pas un répertoire."
exit 1
fi
rm -f "$FILE"
find "$REP" -type f -exec md5sum -b {} \; > "$FILE"
DOUBLON=0
for file in $(cat "$FILE" | sort | awk '{print $1}' | uniq -d); do
DOUBLON=1
echo "Empreinte MD5 identique : $file"
grep $file "$FILE" | cut -d' ' -f2
done
if [ "$DOUBLON" -eq 0 ]; then echo "Aucun doublon trouvé"; fi
logger -t $0 Fin d\'exécution du script
exit 0
Pré-requis pour que le script suivant fonctionne :
1 - Paramétrer sur le poste à sauvegarder un accès ssh au serveur de sauvegarde via un système d'authentification par clé privée / publique.
Tout est expliqué ici : http://quennec.fr/linux/utilisation/connexion-a-une-machine-distante-sans-saisir-le-mot-de-passe
2 - Le programme bzip2 doit être installé sur le poste à sauvegarder.
$ apt-get install bzip2
3 - Rendre les scripts exécutables
$ chmod +x uploadBackup.sh && chmod +x fonctions.inc.sh
Script d'archivage incrémental et transfert sftp automatique
Ce script permet d'effectuer une sauvegarde incrémentale d'un répertoire vers un serveur de sauvegarde.
Il utilise un système de niveau correspondant au jour du mois - 1.
Tous les 1er de chaque mois, une sauvegarde totale (niveau 0) est effectuée.
Une sauvegarde incrémentale est effectuée les jours suivants.
Le script est composé de 2 fichiers.
Un fichier comportant le script principal (uploadBackup.sh) et un fichier comportant les fonctions personnalisées utiles au script principal (fonctions.inc.sh).
Les fichiers à sauvegarder (variable DATADIR) sont enregistrés dans une archive CPIO compressée avec BZIP2 et stockée dans un répertoire local sur le poste à sauvegarder (variable ARCHIVEDIR).
Avant chaque sauvegarde, un fichier de niveau est créé dans le répertoire local.
Toutes les logs sont enregistrées dans un fichier stocké également dans le répertoire local.
La sauvegarde incrémentale utilise le fichier niveau précédent afin de sauvegarder tous les fichiers modifiés depuis la sauvegarde précédente grâce à la commande find et l'option -newer.
Enfin, l'archive CPIO est envoyée sur le serveur de sauvegarde (variable serveur_sauvegarde) via SFTP et stockée dans des sous-répertoires correspondant à l'année et au mois de la sauvegarde dans le dossier de sauvegarde (variable dossier_distant) .
Détail du fichier uploadBackup.sh
$ nl uploadBackup.sh
1 #!/bin/bash
2 # set -x
3 # Répertoire des scripts shell
4 SCRIPTDIR="/root/script_archivage_incremental"
5 # Répertoire des fichiers à sauvegarder
6 DATADIR="/root/dossier_a_sauvegarder"
7 # Répertoire local des archives
8 ARCHIVEDIR="/root/local_backup"
9 # Inclure les fonctions
10 . $SCRIPTDIR/fonctions.inc.sh
11 # Fichier de log
12 LOG=$ARCHIVEDIR/`getDate`.log
13 # Redirection de toutes les sorties du script vers le fichier de log
14 exec 1>$LOG 2>&1
15 # Déterminer le niveau de sauvegarde
16 # Le 1er du mois => niveau 0
17 jourDuMois=`getDayForCalcul`
18 ((niveau=$jourDuMois-1))
19 case $niveau in
20 0) # Sauvegarde totale
21 # Nettoyage du répertoire d'archive
22 rm -i $ARCHIVEDIR/*.bz2 $ARCHIVEDIR/niveau*
23 # Création du fichier de niveau (niveau 0)
24 touch $ARCHIVEDIR/niveau0
25 archive="$ARCHIVEDIR/`getDate`_niveau0.cpio"
26 find $DATADIR | cpio -ocv | bzip2 -c > $archive.bz2
27 ;;
28 *)
29 # Creation du fichier de niveau
30 touch $ARCHIVEDIR/niveau$niveau
31 archive="$ARCHIVEDIR/`getDate`_niveau${niveau}.cpio"
32 # Determination du niveau precedent
33 ((niveauPrec=$niveau-1))
34 # Test si le fichier de niveau precedent existe
35 if [[ ! -f $ARCHIVEDIR/niveau$niveauPrec ]]
36 then
37 # Si il n'existe pas, sauvegarde integrale du repertoire
38 echo "Fichier de niveau $niveauPrec inexistant"
39 echo "Execution d'une sauvegarde integrale en cours de mois"
40 find $DATADIR | cpio -ocv | bzip2 -c > $archive.bz2
41 else
42 # Sauvegarde incrementale
43 find $DATADIR -newer $ARCHIVEDIR/niveau$niveauPrec | cpio -ocv | bzip2 -c > $archive.bz2
44 fi
45 ;;
46 esac
47 # Vérification de la validité de l'archive
48 if isArchiveInvalide $archive.bz2 ; then
49 echo "Archive $archive.bz2 INVALIDE - Fichier non transfere"
50 exit 1
51 fi
52 # Transfert du fichier vers le serveur de sauvegarde
53 if transfert ${archive}.bz2 ; then
54 echo "Transfert realise avec succes"
55 exit 0
56 fi
57 # Si le transfert a echoue
58 echo "Echec de transfert"
59 exit 1
$
Détail du fichier fonctions.inc.sh
$ nl fonctions.inc.sh
1 #!/bin/bash
2 function transfert {
3 typeset mois
4 typeset annee
5 # Recuperation de la valeur du premier argument passe a la fonction
6 # Recuperation du nom de l'archive a envoyer au serveur de sauvegarde
7 typeset ficATransferer=$1
8 # Adresse du serveur de sauvegarde
9 typeset serveur_sauvegarde="192.168.1.113"
10 # Compte utilise pour se connecter au serveur de sauvegarde
11 typeset user="root"
12 # Chemin absolu du dossier ou sera stocke la sauvegarde
13 typeset dossier_distant="/root/sauvegarde_dossier"
14 mois=`getMonth`
15 annee=`getYear`
16 # Test si le dossier de sauvegarde existe sur le serveur de sauvegarde
17 # Connexion au serveur avec le user root
18 ssh $user@$serveur_sauvegarde test -d $dossier_distant/$annee/$mois
19 # Test sur le code retour de la commande precedente
20 case $? in
21 0)
22 ;;
23 255)
24 echo "Echec de la commande SSH"
25 return 1
26 ;;
27 *)
28 # Si code retour different de 0 et 255
29 # Creation du repertoire de la sauvegarde
30 ssh $user@$serveur_sauvegarde mkdir -p $dossier_distant/$annee/$mois
31 ;;
32 esac
33 # Connexion au serveur de sauvegarde en FTP sécurisé
34 # Ne pas oublier les doubles chevrons << avant le mot cle FIN
35 # Ne pas mettre d'espace entre << et FIN
36 sftp -b - $user@$serveur_sauvegarde <<FIN
37 # Positionnement dans le repertoire de la sauvegarde
38 cd $dossier_distant/$annee/$mois
39 pwd
40 # Envoi de la sauvegarde
41 put $ficATransferer
42 FIN
43 # Ne pas mettre de tabulation ou d'espace devant le mot clé FIN
44 # Sinon celui-ci n'est pas reconnu
45 # Test sur le code retour de la commande SFTP
46 # Si le code retour est different de 0
47 # Une anomalie a ete rencontree
48 (( $? != 0 )) && return 1
49 # Tester si archive valide sur serveur de sauvegarde
50 ficSurMachineCible=$(basename $ficATransferer)
51 ssh $user@$serveur_sauvegarde bzip2 -t $dossier_distant/$annee/$mois/$ficSurMachineCible
52 case $? in
53 0)
54 ;;
55 255)
56 echo "Echec de la commande SSH"
57 return 1
58 ;;
59 *)
60 # Si code retour different de 0 et 255
61 # Alors l'archive est invalide
62 echo "Archive $dossier_distant/$annee/$mois/$ficSurMachineCible INVALIDE"
63 return 1
64 ;;
65 esac
66 return 0
67 }
68 function isArchiveInvalide {
69 typeset archive=$1
70 bzip2 -t $archive 2>/dev/null && return 1
71 return 0
72 }
73 function getDate {
74 date '+%Y_%m_%d'
75 }
76 function getYear {
77 date '+%Y'
78 }
79 function getMonth {
80 date '+%m'
81 }
82 function getDayForCalcul {
83 date '+%e' | sed 's/ //'
84 }
$
Quand on développe des scripts pour soi-même, toutes les commandes utilisées dans le script sont obligatoirement installées sur le système. Mais qu'en est-il si le script est partagé avec différentes personnes sur différents sytèmes ?
Il faut être sûr et certain que le script sera utilisable n'importe où et par n'importe qui.
C'est pour cette raison que j'utilise de plus en plus cette fonction dans mes scripts.
function preRequis {
for arg in $@; do
if ! which $arg >/dev/null; then
echo "La commande $arg n'est pas installée !!!"
echo "Fin du script."
exit 1
fi
done
}
Cette fonction, je l'ai appelé "preRequis". Elle reçoit des noms de commandes en arguments et vérifie à l'aide de la commande which (commande primitive du shell) l'existence sur le système de ces commandes.
Grâce à cette fonction, si une personne exécute un script contenant une commande qui n'est pas installée sur son système, un message explicite sera affiché à l'écran.
Cette fonction peut être intégrée dans n'importe quel script.
$ cat sauvegarde_differentielle.sh
#!/bin/bash
function preRequis {
for arg in $@; do
if ! which $arg >/dev/null; then
echo "La commande $arg n'est pas installée !!!"
echo "Fin du script."
exit 1
fi
done
}
preRequis nice rdiff-backup
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
exec 1>>/var/log/sauvegarde_differentielle.log
exec 2>>/var/log/sauvegarde_differentielle_error.log
nice -n 19 rdiff-backup /repertoire_a_sauvegarder /destination_de_la_sauvegarde && nice -n 19 rdiff-backup --remove-older-than 1W --force /destination_de_la_sauvegarde
exit 0
$
Dans cet exemple, j'utilise la fonction preRequis pour vérifier que les commandes nice et rdiff-backup sont bien installées sur le système.
Voici un script qui se charge de vérifier les différences qu'il peut y avoir sur une page web entre 2 périodes de temps définies.
$ nl check_url.sh
1 #!/bin/bash
2 export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
3 URL="http://quennec.fr"
4 PREC="/root/precedent"
5 SUIV="/root/suivant"
6 exec 1>/dev/null 2>&1
7 if [ -e $SUIV ]; then
8 rm $SUIV
9 fi
10 curl $URL > $SUIV
11 if [ -e $PREC ]; then
12 diff $SUIV $PREC
13 if [ $? == 1 ]; then
14 mail -s "Ecart sur la page $URL" ronan@quennec.fr<<EOF
15 EOF
16 fi
17 fi
18 if [ -e $PREC ]; then
19 rm $PREC
20 fi
21 mv $SUIV $PREC
22 exit 0
$
Lignes 2 à 5 : initialisation des variables utilisées dans le script.
Ligne 6 : Redirection des entrées et sorties standards.
Ligne 7 à 9 : Suppression du fichier $SUIV si celui-ci existe.
Ligne 10 : Téléchargement du contenu de la page web et enregistrement dans le fichier $SUIV
Ligne 11 à 17 : Si le fichier $PREC existe, le programme diff compare les 2 fichiers $SUIV et $PREC. Si il y a des différences ($? == 1), un mail est envoyé à l'adresse indiquée.
Ligne 18 à 20 : Si le fichier $PREC existe, il est supprimé.
Ligne 21 : Le fichier $SUIV est renommé en $PREC.
Rendre le script exécutable :
$ chmod +x check_url.sh
Reste à exécuter le script
$ ./check_url.sh
Pour l'automatisation, une ligne sera ajoutée à crontab :
$ crontab -e
*/5 * * * * /root/check_url.sh
Le script sera exécuté toutes les 5 minutes.
Fichier attaché | Taille |
---|---|
check_url.sh_.txt | 460 octets |
Pour accéder à distance au bureau Ubuntu ou d'une autre ditribution Linux même si la session est verouillée, il faut utiliser vnc4server
1 - Installer vnc4server
$ sudo apt-get install vnc4server
2 - Création du répertoire .vnc dans le home
$ cd ~
$ mkdir .vnc
3 - Création du fichier xstartup dans le répertoire .vnc avec des droits d'exécution
$ touch .vnc/xstartup
$ chmod a+x .vnc/xstartup
4 - Edition du fichier xstartup
$ gedit ~/.vnc/xstartup
5 - Y inscrire ce contenu
#!/bin/sh
# Uncomment the following two lines for normal desktop:
unset SESSION_MANAGER
exec sh /etc/X11/xinit/xinitrc
[ -x /etc/vnc/xstartup ] && exec /etc/vnc/xstartup
[ -r $HOME/.Xresources ] && xrdb $HOME/.Xresources
xsetroot -solid grey
vncconfig -iconic &
xterm -geometry 80x24+10+10 -ls -title "$VNCDESKTOP Desktop" &
#twm &
gnome-session &
Il est possible, également, d'utiliser sous GNU/Linux le programme xrdp qui émule parfaitement le protocole RDP (Remote Desktop Protocol Server).
$ apt-get install xrdp
Pour la connexion, n'importe quel client de connexions bureau à distance compatible RDP peut être utiliser.
Le très célèbre mstsc de Windows, mRemoteNG, Remmina (installé par défaut dans Ubuntu depuis la 12.04) etc etc...
Par défaut, le verrouillage du pavé numérique n'est pas activé.
Pour le faire, installer le paquet numlockx
$ sudo apt-get install numlockx
Ensuite, éditer le fichier /etc/gdm/Init/Default
$ sudo gedit /etc/gdm/Init/Default
Ajouter les lignes suivantes à la fin du fichier avant la ligne "exit 0"
L'enchainement des commandes suivantes permet d'afficher à l'écran toutes les adresses ip bloquées par iptables, triées numériquement et numérotées :
$ iptables -L -n | grep 'DROP' | awk '{print $4}' | sort -n | uniq | nl
1 37.59.20.164
2 61.38.252.112
3 85.118.62.43
4 91.236.74.176
5 91.236.74.249
6 93.182.139.42
7 93.182.147.141
8 93.182.174.159
9 93.182.175.25
10 117.21.225.66
11 173.242.126.130
12 199.15.234.138
13 199.15.234.143
14 199.15.234.145
15 199.15.234.146
16 199.15.234.147
17 199.15.234.213
18 208.177.72.206
$
La commande suivante permet d'afficher les règles iptables (option -L) avec les ip au format numérique (option -n) :
$ iptables -L -n
Chain INPUT (policy ACCEPT)
target prot opt source destination
DROP all -- 173.242.126.130 0.0.0.0/0
DROP all -- 199.15.234.146 0.0.0.0/0
DROP all -- 93.182.139.42 0.0.0.0/0
DROP all -- 93.182.175.25 0.0.0.0/0
DROP all -- 93.182.174.159 0.0.0.0/0
DROP all -- 93.182.147.141 0.0.0.0/0
DROP all -- 208.177.72.206 0.0.0.0/0
DROP all -- 199.15.234.138 0.0.0.0/0
DROP all -- 91.236.74.176 0.0.0.0/0
DROP all -- 85.118.62.43 0.0.0.0/0
DROP all -- 91.236.74.249 0.0.0.0/0
DROP all -- 37.59.20.164 0.0.0.0/0
DROP all -- 117.21.225.66 0.0.0.0/0
DROP all -- 199.15.234.143 0.0.0.0/0
DROP all -- 199.15.234.145 0.0.0.0/0
DROP all -- 199.15.234.147 0.0.0.0/0
DROP all -- 61.38.252.112 0.0.0.0/0
DROP all -- 199.15.234.213 0.0.0.0/0
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Suivi de la commande suivante, seules les chaines DROP sont affichées :
$ iptables -L -n | grep 'DROP'
DROP all -- 173.242.126.130 0.0.0.0/0
DROP all -- 199.15.234.146 0.0.0.0/0
DROP all -- 93.182.139.42 0.0.0.0/0
DROP all -- 93.182.175.25 0.0.0.0/0
DROP all -- 93.182.174.159 0.0.0.0/0
DROP all -- 93.182.147.141 0.0.0.0/0
DROP all -- 208.177.72.206 0.0.0.0/0
DROP all -- 199.15.234.138 0.0.0.0/0
DROP all -- 91.236.74.176 0.0.0.0/0
DROP all -- 85.118.62.43 0.0.0.0/0
DROP all -- 91.236.74.249 0.0.0.0/0
DROP all -- 37.59.20.164 0.0.0.0/0
DROP all -- 117.21.225.66 0.0.0.0/0
DROP all -- 199.15.234.143 0.0.0.0/0
DROP all -- 199.15.234.145 0.0.0.0/0
DROP all -- 199.15.234.147 0.0.0.0/0
DROP all -- 61.38.252.112 0.0.0.0/0
DROP all -- 199.15.234.213 0.0.0.0/0
Suivi de la commande suivante, seule la 4ème colonne (celle contenant les ip) est affichées :
$ iptables -L -n | grep 'DROP' | awk '{print $4}'
173.242.126.130
199.15.234.146
93.182.139.42
93.182.175.25
93.182.174.159
93.182.147.141
208.177.72.206
199.15.234.138
91.236.74.176
85.118.62.43
91.236.74.249
37.59.20.164
117.21.225.66
199.15.234.143
199.15.234.145
199.15.234.147
61.38.252.112
199.15.234.213
Suivi de la commande suivante (sort), les ip sont triées numériquement (option -n) et les doublons sont exclus avec la commande uniq:
$ iptables -L -n | grep 'DROP' | awk '{print $4}' | sort -n | uniq
37.59.20.164
61.38.252.112
85.118.62.43
91.236.74.176
91.236.74.249
93.182.139.42
93.182.147.141
93.182.174.159
93.182.175.25
117.21.225.66
173.242.126.130
199.15.234.138
199.15.234.143
199.15.234.145
199.15.234.146
199.15.234.147
199.15.234.213
208.177.72.206
Enfin, la commande suivante numérote toutes les lignes affichées :
$ iptables -L -n | grep 'DROP' | awk '{print $4}' | sort -n | uniq | nl
1 37.59.20.164
2 61.38.252.112
3 85.118.62.43
4 91.236.74.176
5 91.236.74.249
6 93.182.139.42
7 93.182.147.141
8 93.182.174.159
9 93.182.175.25
10 117.21.225.66
11 173.242.126.130
12 199.15.234.138
13 199.15.234.143
14 199.15.234.145
15 199.15.234.146
16 199.15.234.147
17 199.15.234.213
18 208.177.72.206
Au total, ce sont donc 5 commandes qui sont utilisées pour afficher le résultat souhaité.
Si la liste est trop longue pour être affichée en une seule fois, une petite commande supplémentaire fera très bien l'affaire :
$ iptables -L -n | grep 'DROP' | awk '{print $4}' | sort -n | uniq | nl | less
Pré-requis :
Installer le programme ccze
$ apt-get install ccze
Utilisation :
$ tail -f /var/log/apache2/access.log | ccze
La commande tail permet d'afficher les 10 dernières lignes d'un fichier.
L'option -f associée à la commande tail permet d'afficher le fichier en continu.
Enfin, l'envoi à la commande ccze via un tube permet la colorisation des données.
Astuce supplémentaire :
Dans les logs du proxy Squid, la date et l'heure sont enregistrés au format timestamp.
Pas très pratique à lire.
Pour convertir le timestamp dans un format plus lisible pour l'homme, il suffit d'utiliser la commande ccze avec l'option -C
$ tail -f /var/log/squid/access.log | ccze -C
Pour filtrer en continu uniquement les adresses IP des logs Apache, saisir les commandes suivantes :
$ tail -f /var/log/apache2/access.log | egrep -o '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'
ou
$ tail -f /var/log/apache2/access.log | egrep -o '^([0-9]{1,3}\.){3}[0-9]{1,3}'
La commande tail suivie de l'option -f permet d'afficher le contenu d'un fichier en continu.
La commande egrep suivie de l'option -o permet d'afficher uniquement la regex recherchée.
Voici les deux manières les plus simple pour ajouter une clé au gestionnaire des clés APT.
Exemple avec la clé webmin.
1 - On télécharge le fichier contenant la clé :
$ wget http://www.webmin.com/jcameron-key.asc
2 - On ajoute la clé contenu dans le fichier :
$ sudo apt-key add jcameron-key.asc
Sinon, en envoyant la clé récupérée par la commande wget directement à la commande apt-key en passant par un tube :
$ wget -O- http://www.webmin.com/jcameron-key.asc | sudo apt-key add -
Pour lister toutes les clés installées dans le gestionnaire :
$ sudo apt-key list
Pour supprimer une clé :
Récupérer l'identifiant public de la clé à supprimer avec l'option list de la commande apt-key :
$ sudo apt-key list
Par exemple, pour la clé webmin, son identifiant public est le "1024D/11F63C51"
On supprime la clé avec la commande suivante :
$ sudo apt-key del 11F63C51
Sous Linux, la commande ftp permet de se connecter à un serveur FTP.
Pour le mode passif, il est possible d'utiliser directement la commande pftp.
$ ftp mon-serveur-ftp.com
Les informations de connexions, utilisateur et mot de passe, doivent ensuite être saisis.
Pour éviter ce comportement et permettre l'authentification automatique, il est nécessaire de créer le fichier ~/.netrc avec les informations suivantes:
$ cat ~/.netrc
machine mon-serveur-ftp.com login mon-login password mot-mot-de-passe
Et ne pas oublier de modifier les permissions du fichier comme suit:
$ chmod 600 ~/.netrc
Et voilà, plus besoin de saisir son nom d'utilisateur et son mot de passe
Pour X raisons, il peut être intéressant d'avoir une session automatiquement ouverte au démarrage du serveur.
Pour activer cette option :
1 - Localiser le programme login
# which login
/bin/login
2 - Modifier le fichier /etc/inittab
# vim /etc/inittab
Pour une ouverture de session automatique sur la console tty6 (par exemple), commenter la ligne :
#6:23:respawn:/sbin/getty 38400 tty6
Et ajouter au dessous de cette ligne :
6:23:respawn:/bin/login -f root tty6 </dev/tty6 >/dev/tty6 2>&1
Attention à renseigner correctement le chemin d'accès au programme login (/bin/login) obtenu grâce à la commande `which login` ci-dessus et le numéro de la console à utiliser (tty6).
3 - Sauvegarder les modifications et redémarrer le serveur (pour vérification).
Une session root devrait être automatiquement ouverte sur la console tty6.
Pour rappel, sur une version serveur, il existe 6 consoles (tty1 ... tty6).
Pour basculer d'une console à une autre, il suffit d'utiliser les combinaisons de touches suivantes [ctrl]+[alt]+[F1] pour la console tty1, [ctrl]+[alt]+[F2] pour la console tty2 et ainsi de suite jusqu'à [ctrl]+[alt]+[F6] pour la console tty6.
Il est possible d'exécuter une requête MySql en BASH grâce à la commande echo et au client MySql.
Inconvénient
Mot de passe en clair dans la commande.
Avantage
Automatisation possible avec crontab.
Pré-requis
Un client MySql installé sur la poste
$ apt-get install mysql-client
Au préalable
En fonction de l'inconvénient cité ci-dessus, il est conseillé de créer un utilisateur MySql spécifique pour l'occasion. C'est à dire, un utilisateur ayant uniquement le privilège "SELECT" sur la base à utiliser. Affiner les privilèges sur les champs d'une table de la base pour plus de sécurité.
Pour cela, plusieurs solutions :
Exemple en ligne de commande :
Dans l'exemple, je souhaite utiliser les champs "champ1", "champ3" et "champ6" de la table "ma_table" de la base "ma_base". Je créé un user "toto" avec le mot de passe "pass" ayant le privilège "SELECT" sur les champs "champ1", "champ3" et "champ6" de la table "ma_table" de la base "ma_base". Pour terminer, je recharge les privilèges.
$ mysql -u root -p
mysql> CREATE USER 'toto'@'%' IDENTIFIED BY 'pass';
Query OK, 0 rows affected (0.00 sec)
mysql> GRANT SELECT ( `champ1` , `champ3` , `champ6` ) ON `ma_base`.`ma_table` TO 'toto'@'%';
Query OK, 0 rows affected (0.00 sec)
mysql> FLUSH PRIVILEGES ;
Query OK, 0 rows affected (0.00 sec)
mysql> Bye
$
Exemple
Dans l'exemple ci-dessous, je vais donc effectuer une requête avec echo et le client MySql sur les champs "champ1", "champ3" et "champ6" de la table "ma_table" de la base "ma_base" sur mon serveur MySql avec l'utilisateur toto, mettre le résultat en forme grâce à awk et à la commande pr et enfin, envoyer le résulat par mail avec la commande mail.
$ echo "select champ1, champ3, champ6 from ma_base.ma_table order by 3 desc;" | mysql -h mon_serveur_mysql -u toto -ppass | awk 'BEGIN{printf("%-15s %-35s %-5s\n","COL1","COL2","COL3")}NR>1{printf("%15d %-35s %5d\n",$1,$2,$3)}' | pr -h "Le resultat de ma requete SQL" | mail -s "Le resultat de ma requete SQL" moi@domaine.fr
Avec la commande awk, j'ajoute des en-têtes de champs personnalisés dans la section BEGIN et je récupère uniquement les données de la requête en supprimant la première ligne qui contient les noms des champs MySql (NR>1) et le tout mis en forme avec la fonction printf.
Pour ne pas afficher la première ligne contenant le nom des champs, il est également possible d'utiliser la commande mysql avec l'option -N.
Avec la commande pr et l'option -h, j'ajoute un titre à mon rapport.
Petite astuce trouvée sur le site http://www.it-connect.fr/ajouter-un-horodatage-a-la-commande-history/
Sous Linux, la commande history permet d'afficher l'historique des commandes utilisées dans le shell.
$ history
475 java sdz1
476 ll -tr
477 cat tokill.java
478 ll
479 ll -tr
480 vim sdz1.class
481 java sdz1.class
482 java sdz1
483 w
Pour ajouter l'horodatage, il suffit d'ajouter cette ligne au fichier .bashrc
$ echo 'export HISTTIMEFORMAT="%F %T : "' >> ~/.bashrc
Résultat, après s'être bien-sûr reconnecté
$ history
472 2016-11-03 11:51:45 : java sdz1
473 2016-11-03 11:51:45 : ll -tr
474 2016-11-03 11:51:45 : cat tokill.java
475 2016-11-03 11:51:45 : ll
476 2016-11-03 11:51:45 : ll -tr
477 2016-11-03 11:51:45 : vim sdz1.class
478 2016-11-03 11:51:45 : java sdz1.class
479 2016-11-03 11:51:45 : java sdz1
480 2016-11-03 11:51:45 : w
A l'aide de la commande grep, il est très facile de retrouver une commande exécutée un jour précis, voir même à une heure précise.
Voici quelques fonctions bien utiles permettant de manipuler différentes variables et pouvant être inclues dans des scripts.
Le script est disponible ici.
Par exemple, vérifier qu'une variable est numérique, qu'une variable est de type int, qu'une variable est un booléen etc etc...
Ces fonctions (quelques unes) ont été inspirées de PHP.
Ce script peut être inclu dans d'autres scripts de cette manière (l'une ou l'autre des deux méthodes):
source functions.inc
. functions.inc
Le fichier peut également être inclu dans le fichier ~/.bashrc (de la même manière) afin de disposer de toutes ces fonctions directement dans le prompt.
Exemples:
$ is_numeric azerty ; echo $?
1
$ is_numeric ee55ee ; echo $?
1
$ is_numeric 65465484 ; echo $?
0
N'hésiter pas à me faire part de vos commentaires.
Penser à vérifier régulièrement si des nouvelles fonctions ont été ajoutées.
Si vous avez des idées de nouvelles fonctions, partager les.
Les commandes suivantes permettent de redimensionner tout un lot d'images (jpg/png) en indiquant une taille maximum à ne pas dépasser pour la largeur et la hauteur.
Les commandes identify et mogrify sont disponibles dans le paquet imagemagick.
Dans l'exemple suivant, je vais redimensionner toutes les images PNG avec une taille de 700px maxi pour la largeur et la hauteur.
# identify *.png | awk '{split($3, TAB, "x"); W = TAB[1]; H = TAB[2]; if(W > 700){system("mogrify -resize 700x "$1)} if (H > 700){system("mogrify -resize x700 "$1)}}'
Explications:
La commande identify permet d'afficher les caractéristiques d'une ou plusieurs images.
A l'aide de la commande awk, on extrait les dimensions de l'image (fonction split) et si la largeur est supérieur à 700px on redimensionne l'image (700x) à l'aide de la commande mogrify (via la fonction system) - Idem pour la hauteur de l'image (x700).
La commande mogrify modifie directement le fichier d'origine.
Plus de détail ici sur les commandes imagemagick.
Avec bash, pour effectuer ce genre de regex avec grep, j'ai trouvé l'astuce suivante:
# cat monfichier.xml | tr -d "\n" | grep -Po "<desc>.*?</desc>"
Dans mon fichier xml, mes balises <desc> sont étalées sur 3 lignes
...
<desc>
13.0 km, 0:13
</desc>
<desc>
4.0 km, 0:6
</desc>
...
du coup, pour les extraire correctement de mon fichier, je suis obligé de faire une recherche avec une regex qui ne tient pas compte des retours à la ligne et qui n'est surtout pas gourmande (non-greedy) afin de ne pas extraire en une seule fois toutes les balises <desc>
Pour le problème des retours à la ligne, j'utilise la commande tr pour les supprimer.
Pour le problème du "non-greedy", j'utilise grep avec l'option -P, afin d'indiquer à grep d'utiliser la regex comme une regex Perl pour pouvoir interpréter correctement l'indicateur "?" qui permet justement d'obtenir le comportement "non-greedy"
Créer une configuration propre à chaque session SSH est très utile dans le cas où les paramètres de connexions sont très hétérogènes.
Par exemple:
1 - Connexion SSH sur le serveur A avec le user USERA sur le port 2000
2 - Connexion SSH sur le serveur B avec le user USERA sur le port 22
3 - Connexion SSH sur le serveur C avec le user USERB sur le port 443 via un proxy
etc etc...
Ca fait beaucoup de paramètres à mémoriser pour chaque connexion.
Il existe donc un fichier config se trouvant dans le répertoire utilisateur ~/.ssh/ (le créer s'il n'existe pas) et dans lequel il est possible d'y paramétrer toutes les connexions SSH.
voir man 5 ssh_config pour plus de détail.
Détail de la config pour la connexion 1 (en rouge, les paramètres à modifier):
Host serveurA
Hostname mon.serveur.mon.domaine.com (ou l'ip 10.10.10.10)
User USERA
Port 2000 TCPKeepAlive yes
Bien respecter l'indentation
La variable Host accepte n'importe quelle valeur. C'est un identifiant pour le serveur.
La variable Hostname correspond au serveur distant sur lequel on se connecte. On peut y renseigner soit un nom de domaine soit une adresse IP.
La variable User correspond au user avec lequel on se connecte.
La variable Port correspond au port sur lequel on se connecte.
En fonction de cette configuration, la connexion SSH au serveur A s'effectue de cette manière:
$ ssh serveurA
On précise donc uniquement le nom renseigné dans la variable Host du fichier ~/.ssh/config
Détail de la config pour la connexion 3 (en rouge, les paramètres à modifier):
Host serveurC
Hostname mon.serveur.mon.domaine.com (ou l'ip 12.12.12.12)
User USERB
Port 443 TCPKeepAlive yes
ProxyCommand corkscrew proxy.domaine.com 8080 %h %p
La variable ProxyCommand contient la ligne de commande à exécuter pour se connecter via le proxy indiqué en rouge. La commande utilise le programme corkscrew. Penser à l'installer s'il ne l'est pas déjà.
$ apt-get install corkscrew
Pour se connecter au serveur C:
$ ssh serveurC
C'est quand même vachement simple ;)
Pour pouvoir se connecter à une machine distante sans être obligé de saisir un mot de passe, il faut utiliser un système d'authentification par clé privée / publique.
Ce système est très pratique dans le cas où vous utilisez les commandes ssh, scp et sftp dans des scripts.
Pour cela, il suffit d'utiliser la commande ssh-keygen.
Pré-requis :
Avoir un client SSH sur le poste client (openssh-client installé par défaut sur Ubuntu)
Sinon, installé le paquet suivant :
$ sudo apt-get install openssh-client
Avoir un serveur SSH sur la machine distante.
Installé, par exemple, openssh-server :
$ sudo apt-get install openssh-server
Génération d'une paire de clé privée / publique sur la machine client :
Dans l'exemple suivant, le poste client se nomme zeus et la machine distante zimbra.
$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):# Laisser la valeur par défaut
Enter passphrase (empty for no passphrase):# Appuyer directement sur "Entrée"
Enter same passphrase again:# Appuyer directement sur "Entrée"
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
a0:f3:e4:93:12:c4:41:5e:f3:ea:23:0e:79:f0:02:35 root@zeus
The key's randomart image is:
+--[ RSA 2048]----+
| .o o |
| o o o |
| E + . . |
| . o . o |
|. . + o S |
| . + B . |
| + = B |
| = o o |
| . |
+-----------------+
$
Vérifier que les clés privée et publique ont bien été créées :
Les clés id_rsa et id_rsa.pub sont générées dans le répertoire $HOME/.ssh
$ cd $HOME/.ssh
$ ls -l
total 16
-rw------- 1 root root 1675 2011-12-21 19:43 id_rsa
-rw-r--r-- 1 root root 391 2011-12-21 19:43 id_rsa.pub
-rw-r--r-- 1 root root 4420 2011-11-02 21:25 known_hosts
$
Copier la clé publique id_rsa.pub du poste client dans le réperoire $HOME/.ssh de la machine distante via ssh-copy-id :
$ ssh-copy-id -i id_rsa.pub root@zimbra
root@zimbra's password: # Saisir le mot de passe et appuyer sur "Entrée"
Now try logging into the machine, with "ssh 'root@zimbra'", and check in:
.ssh/authorized_keys
to make sure we haven't added extra keys that you weren't expecting.
$
Comme indiqué dans le message précédent, se connecter au serveur distant afin de vérifier que la clé publique a bien été ajoutée au fichier ".ssh/authorized_keys" (si la procédure a fonctionnée correctement, aucun mot de passe ne doit être demandé) :
$ ssh -l root zimbra
Se rendre dans le répertoire $HOME/.ssh :
$ cd $HOME/.ssh
$ ls -l
total 12
-rw-r--r-- 1 root root 391 2011-12-21 20:40 authorized_keys
-rw-r--r-- 1 root root 442 2011-05-20 08:53 known_hosts
-rw-r--r-- 1 root root 391 2011-12-21 20:26 ma_cle_publique
$ cat authorized_keys # Contenu du fichier "authorized_keys"
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA492yBTCnwE3B7Xws0+bLYJt5G3tBI2P1v1Ld7Alp7FpJmBGzwwF
/dTwv+zh5Xr6ti2ElLQaotKj2YsR8WhFBAQqWcUR4J5/RLhMFttkANVp+3ixeDI8Id609JYcTACMz1h/lOFs38lp17KwwPZW1+tWBFovR4bwVpBNMucbuFy30LsarzdZsWnAiYfU/sLHRm/4cBZq1BF/fHjvaU3PT5NVsEuDyQg3vloW4vkAHErg6CUhp9GEUbBAPXqw== root@zeus
$ exit # On quitte la machine distante
Pour se connecter à un serveur par un autre port que celui par défaut, utiliser la commande suivante :
$ ssh-copy-id -i id_rsa.pub "-p 10022 root@zimbra"
ou
$ ssh-copy-id -i id_rsa.pub -p 10022 root@zimbra
La procédure est terminée.
Vous pouvez désormais vous connecter à cette machine distante via ssh, scp ou sftp sans avoir à saisir un mot de passe.
Par contre, il faut être conscient des risques que cela peut engendrer.
N'importe qui ayant accès à la machine client aura automatiquement accès à la machine distante.
Ceci est à faire dans le cas où vous n'avez pas d'autres solutions.
Voir également cet article.
Dans l'exemple précédent, l'authentification automatique concernait l'utilisateur root de la machine zeus entre l'utilisateur root de la machine zimbra mais il est tout à fait possible de paramétrer une authentification automatique pour des utilisateurs différents entre le poste client et la machine distante.
Exemple :
Paramétrer une authentification automatique entre l'utilisateur toto du poste client client1 et l'utilisateur tutu de la machine distante serveur1.
Pour cela, il suffit de générer les clés privée/publique pour l'utilisateur toto sur le poste client client1 et de copier le contenu de la clé publique id_rsa.pub dans le fichier "authorized_keys" dans le répertoire $HOME/.ssh de l'utilisateur tutu de la machine distante serveur1.
La connexion suivante se fera sans saisie de mot de passe :
toto@client1:~$ ssh -l tutu serveur1
Pour générer des pages HTML colorisées contenant les différentes logs du système, il suffit d'utiliser la commande ccze.
Pour l'installer :
$ apt-get install ccze
Pour créer une page HTML contenant les données du fichier de log /var/log/syslog :
$ ccze -h < /var/log/syslog > /var/www/logsccze/syslog.html
Penser à créer auparavant le répertoire /var/www/logsccze
$ mkdir /var/www/logsccze
Utiliser un navigateur pour admirer le résultat en vous connectant sur votre serveur apache.
Sous Debian/Ubuntu, les paquets sont au format DEB.
A l'inverse, sous Red Hat (et ses dérivés), les paquets sont au format RPM.
Il arrive parfois que les paquets permettant l'installation d'applications ne soient disponible qu'au format RPM.
Pas de panique, sous Debian/Ubuntu, il existe une application qui permet de convertir des paquets RPM en DEB.
Cette application se nomme alien.
Pour l'installer :
$ sudo apt-get install alien
Convertir un paquet RPM en DEB :
$ alien --to-deb package.rpm
Convertir un paquet DEB en RPM :
$ alien --to-rpm package.deb
Convertir un paquet RPM en DEB et l'installer automatiquement :
$ alien -i package.rpm
La conversion vers le format DEB étant la conversion par défaut, il n'est pas nécessaire de le préciser.
Si, lors de l'installation du système, vous avez sous-estimé la taille de la partition d'échange SWAP (il est recommandé d'avoir une partition d'échange SWAP équivalent à la quantité de mémoire vive installée sur le système), il est possible de créer des fichiers supplémentaires post-installation.
Pour l'exemple, je vais créer un fichier SWAP d'1 Go dans le répertoire /mnt (avec le user root)
$ cd /mnt
$ dd if=/dev/zero of=1G.swap bs=1k count=1024000
$ du -sh ./1G.swap
1001M ./1G.swap
$ chmod 600 /mnt/1G.swap
$ mkswap 1G.swap -f
$ swapon /mnt/1G.swap
$ swapon -s
Explications:
Ajuster la configuration du swap
$ cat /proc/sys/vm/swappiness
60
Par défaut, dès 40% d'utilisation de la RAM (60% de mémoire libre), les données sont écrites dans la swap.
Avec un serveur équipé de 16Go de RAM, il est intéressant de diminuer cette valeur.
$ sysctl vm.swappiness=10
Utilisation de la swap à partir de 90% d'utilisation de la ram.
Pour une modification permanente, éditer le fichier /etc/sysctl.conf
$ echo "vm.swappiness=10" >> /etc/sysctl.conf
Dans le cadre d'une gestion de certificats SSL auto signés, il peut-être intéressant d'ajouter son autorité de certification personnelle à la liste des autorités de certification reconnues.
Pour cela, rien de plus simple, créer le dossier perso (par exemple) dans le dossier /usr/share/ca-certificates
# mkdir /usr/share/ca-certificates/perso
Y ajouter son autorité de certification puis modifier le fichier /etc/ca-certificates.conf afin de l'ajouter à la liste
# cat <<EOF >> /etc/ca-certificates.conf
perso/ca-perso-internal.cert
EOF
et pour finir, exécuter la commande de mise à jour
# update-ca-certificates -v
Cette commande a pour effet de recopier les autorités listées dans le fichier /etc/ca-certificates.conf et présentes dans le dossier /usr/share/ca-certificates/... dans le dossier /etc/ssl/certs/
Pour effacer un disque dur de manière sûre, il suffit d'utiliser la commande dd et le fichier spécial /dev/urandom.
Premièrement, il faut identifier le disque à effacer et être certain de ne pas se tromper car la commande dd va détruire tout ce qui se trouve sur le disque.
$ fdisk -l
Disk /dev/sda: 1000.2 GB, 1000204886016 bytes
255 heads, 63 sectors/track, 121601 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disk identifier: 0x00000000
Device Boot Start End Blocks Id System
/dev/sda1 * 1 66 524288 83 Linux
Partition 1 does not end on cylinder boundary.
/dev/sda2 66 121601 976235712 8e Linux LVM
Disk /dev/sdb: 1500.3 GB, 1500299395072 bytes
255 heads, 63 sectors/track, 182401 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00026d5d
Device Boot Start End Blocks Id System
/dev/sdb1 1 182401 1465136001 83 Linux
Disk /dev/sdc: 160.0 GB, 160041885696 bytes
255 heads, 63 sectors/track, 19457 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x0008ef40
Device Boot Start End Blocks Id System
/dev/sdc1 1 19457 156288321 83 Linux
Disk /dev/sdd: 640.1 GB, 640135028736 bytes
255 heads, 63 sectors/track, 77825 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x3d4b96dc
Device Boot Start End Blocks Id System
/dev/sdd1 1 77825 625129312 83 Linux
$
Dans mon cas, je souhaite détruire toutes les données de mon disque de 160 GB. La commande fdisk -l m'indique qu'il s'agit du périphérique /dev/sdc.
J'exécute ensuite la commande suivante :
$ for n in `seq 7`; do dd if=/dev/urandom of=/dev/sdc bs=8b conv=notrunc; done
La commande précédente va donc écrire 7 fois de suite sur tout le disque des données aléatoires rendant ainsi illisible toutes les données précédentes.
Pour coloriser la commande grep, il existe 2 méthodes :
$ cat .bashrc | grep --color=always '^alias'
alias ls='ls $LS_OPTIONS'
alias ll='ls $LS_OPTIONS -la'
alias l='ls $LS_OPTIONS -lA'
alias maj='apt-get update && apt-get upgrade'
$
$ echo "alias grep='grep --color=always'" >> .bashrc
$ cat .bashrc
...
alias grep='grep --color=always'
$
Puis recharger le fichier .bashrc
$ . .bashrc
$
La colorisation sera automatique à chaque utilisation de la commande grep
$ cat .bashrc | grep '^alias'
alias ls='ls $LS_OPTIONS'
alias ll='ls $LS_OPTIONS -la'
alias l='ls $LS_OPTIONS -lA'
alias maj='apt-get update && apt-get upgrade'
alias grep='grep --color=always'
$
Pour forcer la coloration du prompt dans une distribution type Debian, il suffit de décommenter la ligne suivante dans le fichier ~/.bashrc
$ cat .bashrc
...
# uncomment for a colored prompt, if the terminal has the capability; turned
# off by default to not distract the user: the focus in a terminal window
# should be on the output of commands, not on the prompt
force_color_prompt=yes
...
$
Si on utilise un projet GIT via une connexion http(s) nécessitant une authentification, il est donc nécessaire de s'authentifier à chaque pull et commit effectués.
Ca devient vite contraignant au bout d'un moment.
Il est donc possible d'enregistrer dans un fichier les paramètres de connexion.
Le fichier ~/.gitconfig :
[user]
name = monNom
email = monEmail
[credential]
helper = store
[http]
sslVerify = false
postBuffer = 524288000
[credential "http://monDepotGit.com"]
username = monUser
[credential "https://monDepotGit.com"]
username = monUser
- La section [user] contient les infos personnelles (nom, email etc etc ...)
- Le fichier doit contenir la section [credential] avec la variable helper = store
- La section [http] avec la variable sslVerify = false permet de se connecter en https sur un dépot GIT avec un certificat non reconnu (auto-signé)
La variable postBuffer = 524288000 permet de résoudre l'erreur suivante lors des commits:
error: RPC failed; result=22, HTTP code = 411
Cela permettra à tous les projets locaux d'envoyer jusqu'à 500 Mo de données.
- Enfin, la section [credential "adresse http(s)"] contient l'adresse http(s) du dépot GIT ainsi que le username correspondant. La section est répétée autant de fois qu'il y a d'adresses différentes de dépots GIT.
Le fichier ~/.git-credentials :
Ce fichier contient le username associé au mot de passe et à l'adresse http(s) renseignée dans le fichier ~/.gitconfig
Ce fichier doit être lisible uniquement par le user concerné (chmod 0600).
http://monUser:monPassword@monDepotGit.com
https://monUser:monPassword@monDepotGit.com
Si le username et/ou le password contient un des caractères spécifiques à la chaine de connexion (:/@), il est obligatoire de l'écrire en hexadécimal.
@ = %40 en hexadécimal
Sinon, le simple fait de créer le fichier ~/.git-credentials et de lui attribuer le bon mode 0600, il sera automatiquement complété avec le bonne combinaison user:password@adresseHttps à la première utilisation de la comme git pull (par exemple).
Gammu est un utilitaire permettant d'utiliser un téléphone portable via le port USB.
Pour installer gammu :
$ apt-get install gammu
Quelques commandes utiles :
Envoyer un sms
$ echo "Mon premier SMS" | gammu --sendsms TEXT 06xxxxxxxx
Afficher les dossiers SMS du téléphone
$ gammu getsmsfolders
Afficher tous les sms du téléphone
$ gammu getallsms
Astuce :
Un vieux téléphone qui ne sert à rien + une carte sim Free avec un forfait 2H à 0€ = un système de communication pour un serveur afin d'avertir l'administrateur système en cas de défaillance et permettre également à l'administrateur d'envoyer des commandes au serveur. La classe !!!
Par exemple, avertir en cas d'intrusion, démarrer un service SSH ou autre, avertir en cas de défaillance réseau (internet), avertir en cas de coupure de courant (disposer d'un UPS bien sûr) etc etc ... Le potentiel est énorme.
Le seul inconvénient, pour que gammu fonctionne parfaitement (via des scripts exécutés automatiquement), il faut avoir une session constamment ouverte sur le système.
Pour gérer les services qui se lancent automatiquement au démarrage, il suffit d'utiliser le programme SYSV-RC-CONF.
Pour l'installer :
$ sudo apt-get install sysv-rc-conf
Utilisation :
$ sudo sysv-rc-conf
Les services lancés automatiquement au démarrage ont un niveau d'exécution de 2 à 5
Pour désactiver un service au démarrage, il suffit de décocher tous les niveaux d'exécution de 2 à 5 en se positionnant sur les "X" à l'aide des flèches du clavier et en appuyant ensuite sur la barre espace.
Pour faire défiler les pages, il suffit d'appuyer sur les touches CTRL + N pour la page suivante ou CTRL + P pour la page précédente.
CAcert.org est une association qui fourni gratuitement des certificats ssl (signature, chiffrement, connexion, certificats https).
Pour un bon fonctionnement du service, il est nécessaire d'installer les certificats racine de CAcert.org.
Sur Debian/Ubuntu, tous les certificats racine sont installés dans le répertoire /etc/ssl/certs.
Pour x raisons, il peut être nécessaire d'inverser le contenu d'un fichier texte.
Par exemple, pour afficher le contenu d'un fichier de logs dans l'ordre inverse.
Suite à la remarque de barbay, la commande tac permet d'inverser le contenu d'un fichier texte.
$ tac /var/log/syslog
Sinon, pour inverser le contenu d'un fichier texte, il est possible d'utiliser l'enchainement de commandes suivant :
Pour commencer, j'affiche le contenu du fichier avec la commande cat :
$ cat /var/log/syslog
J'enchaine avec la commande nl qui permet de numéroter les lignes du fichier :
$ cat /var/log/syslog | nl
J'enchaine avec la commande sort qui permet de trier le contenu du fichier numériquement (avec l'option -n) et en ordre inverse (avec l'option -r) sur la première colonne du fichier contenant les numéros de lignes générés par la commande nl :
$ cat /var/log/syslog | nl | sort -n -r
Il reste maintenant à supprimer la première colonne du fichier contenant les numéros de lignes avec la commande cut :
$ cat /var/log/syslog | nl | sort -n -r | cut -f2
Et voilà, le fichier s'affiche à l'écran dans l'ordre inverse.
Sous Linux, que ce soit sur une version Desktop ou Server, 6 terminaux sont en permanence à disposition.
Pour les activer, rien de plus simple.
Sur un version Desktop ou Server, les différents terminaux sont accessibles
via les combinaisons des touches suivantes :
Sur une version Desktop, une fois basculé en mode console, il est possible de revenir au mode graphique grâce à la combinaison des touches suivantes :
Le fait d'utiliser la mémoire vive d'une machine comme espace de stockage permet d'accéder aux données à des vitesses défiant toute concurrence.
Si l'avantage est grand, l'inconvénient l'est tout autant. Effectivement, en cas de coupure de courant, toutes les données se trouvant en mémoire vive sont perdues à jamais.
C'est pour cette raison que je préconise l'usage de cette méthode à des fins de lecture uniquement.
Ce qui est déjà un bon compromis.
Un autre inconvénient réside dans le fait que la taille des données à stocker est limitée à la taille de la mémoire vive disponible.
Sur les systèmes récents, la quantité de mémoire vive disponible étant assez conséquente, ça ne devrait donc pas être un problème.
Si vous devez utiliser une base de données sqlite et/ou des fichiers textes pour y lire des données, pourquoi ne pas les stocker dans la mémoire vive afin d'y accéder plus rapidement.
Voici la marche à suivre (on utilise comme type de système de fichier tmpfs):
On créé le répertoire qui servira de point de montage
# mkdir /tmpfs
On monte le répertoire en mémoire
# mount -t tmpfs no-device /tmpfs
Dorénavant, tout ce qui sera stocké dans le répertoire /tmpfs sera automatiquement stocké dans la mémoire vive.
Un petit script au démarrage du système qui se charge d'effectuer le point de montage et d'y copier les fichiers (fichiers textes, base de données sqlite etc etc...) et le tour est joué.
Le site www.iana.org recense la liste complète des extensions de domaines.
Il peut-être utile d'en avoir une copie dans un fichier (pour l'utiliser avec la commande grep par exemple).
Pré requis:
$ apt-get install curl html2text awk
Création du fichier ROOT:
$ curl http://www.iana.org/domains/root/db -o - 2>/dev/null | html2text | awk '$1 ~ "^\\." {printf("\\%s\n",$1)}' > ROOT
$ head ROOT
\.abbott
\.abogado
\.ac
\.academy
\.accountant
\.accountants
\.active
\.actor
\.ad
\.ads
Ce fichier peut ensuite être utilisé avec la commande grep pour filtrer des adresses web par exemple.
$ grep -f ROOT monFichierLog
Un ajout dans crontab permet d'avoir cette liste constamment à jour.
Configurer Postfix sous Ubuntu est un jeu d'enfant grâce à la commande
$ dpkg-reconfigure postfix
Quand il s'agit d'ajouter l'anti-spam spamassassin à la configuration de Postfix, ça se complique un peu.
Dans un premier temps, il faut installer spamassassin
$ apt-get install spamassassin
Il faut ensuite créer le répertoire de spamassassin, ajouter le user et le group suivant au système et enfin régler les permissions sur le répertoire
$ mkdir /var/spool/spamassassin
$ useradd -d /var/spool/spamassassin -s /bin/false spamassassin
$ chown spamassassin:spamassassin /var/spool/spamassassin -Rc
Il faut activer spamassassin en modifiant le fichier suivant comme indiqué
$ cat /etc/default/spamassassin | egrep -v '^(#|$)'
ENABLED=1
OPTIONS="--create-prefs --max-children 5 --helper-home-dir -u spamassassin -g spamassassin"
PIDFILE="/var/run/spamd.pid"
CRON=1
J'ai également modifié le fichier /etc/spamassassin/local.cf afin de ré-écrire le début de l'objet des mails considérés comme du spam
rewrite_header Subject __SPAM__
Redémarrer spamassassin afin de prendre en compte la nouvelle configuration
$ service spamassassin restart
Il faut ensuite modifier le fichier /etc/postfix/master.cf afin d'ajouter les éléments suivants
1 - Remplacer la ligne smtp par celle-ci
smtp inet n - n - - smtpd -o content_filter=spamassassin
2 - A la fin du fichier, ajouter la ligne suivante
spamassassin unix - n n - - pipe user=spamassassin argv=/usr/bin/spamc -f -e /usr/sbin/sendmail -oi -f ${sender} ${recipient}
Reste à redémarrer Postfix
$ service postfix restart
Dorénavant, tous les spams auront la mention __SPAM__ dans l'objet, reste à faire une règle dans son client mail afin de les placer directement dans le dossier spam
Pour un passage de qwerty en azerty
$ loadkeys fr
$ apt-get install console-data (si besoin)
$ dpkg-reconfigure console-setup
$ loadkeys fr
$ dpkg-reconfigure console-data
Pour un passage de azerty en qwerty
$ loadkeys us
$ apt-get install console-data (si besoin)
$ dpkg-reconfigure console-setup
$ loadkeys fr
$ dpkg-reconfigure console-data
Le RAID1 permet de mettre en parallèle au minimum 2 disques durs afin d'avoir une reproduction parfaite des données sur tous les disques de la grappe.
En cas de panne matériel d'un disque, les données restent accessibles grâce aux autres disques.
C'est une excellente solution pour la sécurité des données.
L'inconvénient, l'espace de stockage total est égal à la capacité du plus petit des disques.
Prenons l'exemple d'une grappe de 2 disques d'une capacité de 40 Gb chacun. L'espace de stockage du volume RAID1 sera donc de 40 Gb.
Il n'est pas nécessaire d'avoir des disques de même capacité pour créer un volume RAID1. Il est tout à fait possible de créer un volume RAID1 avec un disque de 30 Gb et un disque de 40 Gb. Il faudra par contre avoir des partitions de même taille. Il faudra donc partitionner le disque le plus grand afin d'avoir une partition de taille identique à celui du plus petit.
Pour l'exemple, je vais créer un RAID1 avec deux disques de 10 Gb chacun. J'utilise Ubuntu 12.04 LTS pour les tests.
Premièrement, lister les disques présents sur le système.
$ fdisk -l
Disk /dev/vda: 10.7 GB, 10737418240 bytes
16 heads, 63 sectors/track, 20805 cylinders, total 20971520 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000
Disk /dev/vda doesn't contain a valid partition table
Disk /dev/vdb: 10.7 GB, 10737418240 bytes
16 heads, 63 sectors/track, 20805 cylinders, total 20971520 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000
Disk /dev/vdb doesn't contain a valid partition table
Mon système contient bien deux disques de 10 Gb correspondant à /dev/vda et /dev/vdb.
Il faut ensuite créer sur chaque disque une partition de type "Linux RAID autodetect".
$ fdisk /dev/vda
La commande "m" du programme fdisk permet d'afficher l'aide.
Nous allons donc ajouter une partition primaire égale à la taille du disque avec la commande "n (add a new partition)" puis la commande "p (primary)".
Je valide ensuite les choix par défaut afin de créer une seule partition sur le disque.
Une fois la partition créée, il faut ensuite modifier le type de la partition avec la commande "t (change a partition's system id)".
Le code correspondant a une partition Linux RAID autodetect est "fd"
Il faut donc saisir "fd" pour le choix de la partition Linux RAID autodetect.
Pour terminer, il faut valider les changements avec la commande "w (write table to disk and exit)".
Répéter l'opération pour le second disque /dev/vdb.
$ fdisk /dev/vdb
Lister à nouveau les disques pour vérifier que nos modifications ont bien été prises en compte.
$ fdisk -l
Disk /dev/vda: 10.7 GB, 10737418240 bytes
2 heads, 17 sectors/track, 616809 cylinders, total 20971520 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x050bac38
Device Boot Start End Blocks Id System
/dev/vda1 2048 20971519 10484736 fd Linux RAID autodetect
Disk /dev/vdb: 10.7 GB, 10737418240 bytes
2 heads, 17 sectors/track, 616809 cylinders, total 20971520 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x8df86189
Device Boot Start End Blocks Id System
/dev/vdb1 2048 20971519 10484736 fd Linux RAID autodetect
Les deux disques /dev/vda et /dev/vdb contiennent bien une partition Linux RAID autodetect /dev/vda1 et /dev/vdb1.
Nous pouvons donc, à présent, créer notre volume RAID1 que nous nommerons /dev/md0.
Pour créer un volume RAID, nous utiliserons le programme mdadm.
Pour l'installer, rien de plus simple.
$ apt-get install mdadm
Nous allons donc créer un volume RAID1 /dev/md0 composé de 2 disques et contenant les 2 partitions /dev/vda1 et /dev/vdb1.
$ mdadm --create /dev/md0 --level=1 --assume-clean --raid-devices=2 /dev/vda1 /dev/vdb1
mdadm: Note: this array has metadata at the start and
may not be suitable as a boot device. If you plan to
store '/boot' on this device please ensure that
your boot-loader understands md/v1.x metadata, or use
--metadata=0.90
Continue creating array?
Continue creating array? (y/n) y
mdadm: Defaulting to version 1.2 metadata
mdadm: array /dev/md0 started.
L'option "--create" indique à mdadm de créer le volume /dev/md0.
L'option "--level=1" indique que nous créons un RAID de type 1.
L'option "--raid-devices=2" indique que le volume est constitué de 2 disques.
Pour terminer, nous indiquons les partitions à insérer dans le volume RAID1 /dev/md0.
La commande "fdisk -l" nous montre notre volume RAID1 que nous venons de créer.
$ fdisk -l
Disk /dev/md0: 10.7 GB, 10727849984 bytes
2 heads, 4 sectors/track, 2619104 cylinders, total 20952832 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000
Disk /dev/md0 doesn't contain a valid partition table
La commande "mdadm --detail /dev/md0" nous montre l'état de notre volume RAID1 /dev/md0.
$ mdadm --detail /dev/md0
/dev/md0:
Version : 1.2
Creation Time : Sat May 18 17:08:08 2013
Raid Level : raid1
Array Size : 10476416 (9.99 GiB 10.73 GB)
Used Dev Size : 10476416 (9.99 GiB 10.73 GB)
Raid Devices : 2
Total Devices : 2
Persistence : Superblock is persistent
Update Time : Sat May 18 17:08:08 2013
State : clean
Active Devices : 2
Working Devices : 2
Failed Devices : 0
Spare Devices : 0
Name : vm-vpn:0 (local to host vm-vpn)
UUID : b131679e:e5b15236:8003d92b:be9f610b
Events : 0
Number Major Minor RaidDevice State
0 253 1 0 active sync /dev/vda1
1 253 17 1 active sync /dev/vdb1
Maintenant que notre volume RAID1 est créé, il nous reste à créer le système de fichier. Nous allons créer un système de fichier EXT4.
$ mkfs.ext4 /dev/md0
mke2fs 1.42 (29-Nov-2011)
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
655360 inodes, 2619104 blocks
130955 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=2684354560
80 block groups
32768 blocks per group, 32768 fragments per group
8192 inodes per group
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632
Allocating group tables: done
Writing inode tables: done
Creating journal (32768 blocks):
done
Writing superblocks and filesystem accounting information: done
Nous pouvons maintenant utiliser notre nouvel espace de stockage. Pour cela nous devons créer un point de montage.
$ mkdir /media/raid
$ mount /dev/md0 /media/raid
$ ll /media/raid
total 24
drwxr-xr-x 3 root root 4096 May 18 22:48 .
drwxr-xr-x 4 root root 4096 May 18 22:59 ..
drwx------ 2 root root 16384 May 18 22:48 lost+found
Pour un montage automatique au démarrage du système, nous devons récupérer l'UUID du volume /dev/md0 ...
$ blkid /dev/md0
/dev/md0: UUID="59fd912b-e1a9-4693-ab91-f7d9eb883bae" TYPE="ext4"
... et enregistrer dans le fichier "/etc/fstab" la ligne suivante
UUID=59fd912b-e1a9-4693-ab91-f7d9eb883bae /media/raid ext4 rw 0 0
Pour finir, enregistrer les informations du raid dans le fichier /etc/mdadm/mdadm.conf :
$ mdadm --detail --scan >> /etc/mdadm/mdadm.conf
Dans l'exemple suivant, je souhaite créer un volume RAID1 qui contiendra les partitions /dev/vda1 et /dev/vdb1.
La partition /dev/vda1 n'existe pas et sera donc créée (Linux RAID autodetect).
La partition /dev/vdb1 existe et est du type Linux avec un système de fichier ext4 et contenant des données qu'il faudra transférer sur le nouveau volume RAID1.
La partition /dev/vdb1 sera ensuite modifiée en Linux RAID autodetect puis intégrée au volume RAID1.
$ fdisk -l
Disk /dev/vda: 10.7 GB, 10737418240 bytes
16 heads, 63 sectors/track, 20805 cylinders, total 20971520 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000
Disk /dev/vda doesn't contain a valid partition table
Disk /dev/vdb: 10.7 GB, 10737418240 bytes
2 heads, 17 sectors/track, 616809 cylinders, total 20971520 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0xb4e1f868
Device Boot Start End Blocks Id System
/dev/vdb1 2048 20971519 10484736 83 Linux
Création d'une partition /dev/vda1 du type Linux RAID autodetect :
$ fdisk /dev/vda
On vérifie que la partition a bien été créée :
$ fdisk -l /dev/vda
Disk /dev/vda: 10.7 GB, 10737418240 bytes
2 heads, 17 sectors/track, 616809 cylinders, total 20971520 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x4ef75a9a
Device Boot Start End Blocks Id System
/dev/vda1 2048 20971519 10484736 fd Linux RAID autodetect
Création du volume RAID1 /dev/md0 et contenant, pour l'instant, uniquement la partition /dev/vda1 (ajout de l'argument "missing" à la place de la seconde partition /dev/vdb1):
$ mdadm --create /dev/md0 --level=1 --assume-clean --raid-devices=2 /dev/vda1 missing
mdadm: Note: this array has metadata at the start and
may not be suitable as a boot device. If you plan to
store '/boot' on this device please ensure that
your boot-loader understands md/v1.x metadata, or use
--metadata=0.90
Continue creating array?
Continue creating array? (y/n) y
mdadm: Defaulting to version 1.2 metadata
mdadm: array /dev/md0 started.
La commande suivante nous montre que notre volume RAID1 /dev/md0 a bien été créé :
$ fdisk -l /dev/md0
Disk /dev/md0: 10.7 GB, 10727849984 bytes
2 heads, 4 sectors/track, 2619104 cylinders, total 20952832 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000
Disk /dev/md0 doesn't contain a valid partition table
La commande suivant nous montre bien l'état dégradé de notre volume RAID1 /dev/md0 :
$ cat /proc/mdstat
Personalities : [linear] [multipath] [raid0] [raid1] [raid6] [raid5] [raid4] [raid10]
md0 : active raid1 vda1[0]
10476416 blocks super 1.2 [2/1] [U_]
unused devices: <none>
Maintenant que notre volume RAID1 est créé, il nous reste à créer le système de fichier. Nous allons créer un système de fichier EXT4.
$ mkfs.ext4 /dev/md0
mke2fs 1.42 (29-Nov-2011)
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
655360 inodes, 2619104 blocks
130955 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=2684354560
80 block groups
32768 blocks per group, 32768 fragments per group
8192 inodes per group
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632
Allocating group tables: done
Writing inode tables: done
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done
Nous pouvons maintenant utiliser notre nouvel espace de stockage. Pour cela nous devons créer un point de montage.
$ mkdir /media/raid
$ mount /dev/md0 /media/raid
$ ll /media/raid
total 24
drwxr-xr-x 3 root root 4096 May 18 22:48 .
drwxr-xr-x 4 root root 4096 May 18 22:59 ..
drwx------ 2 root root 16384 May 18 22:48 lost+found
Nous allons maintenant transférer toutes les données de la partition /dev/vdb1 montée dans le répertoire /mnt vers la partition /dev/md0 montée dans le répertoire /media/raid
$ rsync -av /mnt/* /media/raid/
Une fois les données copiées, il faut démonter la partition /dev/vdb1
$ umount /mnt
Il faut maintenant recopier la table de partition du disque /dev/vda vers le disque /dev/vdb.
$ sfdisk --dump /dev/vda | sfdisk /dev/vdb
$ fdisk -l /dev/vdb
Disk /dev/vdb: 10.7 GB, 10737418240 bytes
16 heads, 63 sectors/track, 20805 cylinders, total 20971520 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0xb4e1f868
Device Boot Start End Blocks Id System
/dev/vdb1 2048 20971519 10484736 fd Linux RAID autodetect
Nous pouvons donc ajouter à notre volume RAID1 /dev/md0 la partition /dev/vdb1
$ mdadm /dev/md0 -a /dev/vdb1
Puis surveiller en temps réel la reconstruction du volume RAID1 /dev/md0
$ watch -n 1 cat /proc/mdstat
Une fois la reconstruction terminée ...
$ cat /proc/mdstat
Personalities : [linear] [multipath] [raid0] [raid1] [raid6] [raid5] [raid4] [raid10]
md0 : active raid1 vdb1[2] vda1[0]
10476416 blocks super 1.2 [2/2] [UU]
unused devices: <none>
... nous récupérons l'UUID du volume /dev/md0 ...
$ blkid /dev/md0
/dev/md0: UUID="e1f4bff2-bbb7-4449-a964-474a6f23495b" TYPE="ext4"
... et nous enregistrons dans le fichier /etc/fstab la ligne suivante :
UUID=e1f4bff2-bbb7-4449-a964-474a6f23495b /media/raid ext4 rw 0 0
pour que notre volume /dev/md0 soit monté automatiquement à chaque démarrage du système.
Dans l'exemple suivant, le disque /dev/vdb est en panne.
La partition /dev/vdb1 intégrée au volume RAID1 /dev/md127 n'est plus accessible.
Dans le cas où la panne ne serait pas détectée par le système, exécuter la commande suivante :
$ mdadm --manage --set-faulty /dev/md127 /dev/vdb1
On vérifie l'état du volume RAID :
$ cat /proc/mdstat
Personalities : [raid1] [linear] [multipath] [raid0] [raid6] [raid5] [raid4] [raid10]
md127 : active raid1 vda1[2] vdb1[1](F)
10476416 blocks super 1.2 [2/1] [U_]
unused devices: <none>
La partition /dev/vdb1 est bien indiquée comme n'étant plus accessible (flag à F).
On supprime la partition /dev/vdb1 du volume RAID /dev/md127 :
$ mdadm /dev/md127 -r /dev/vdb1
mdadm: hot removed /dev/vdb1 from /dev/md127
On vérifie que la partition /dev/vdb1 a bien été supprimée :
$ cat /proc/mdstat
Personalities : [raid1] [linear] [multipath] [raid0] [raid6] [raid5] [raid4] [raid10]
md127 : active raid1 vda1[2]
10476416 blocks super 1.2 [2/1] [U_]
unused devices: <none>
La partition n'apparait plus.
Il faut maintenant arrêter la machine, remplacer le disque défectueux puis redémarrer la machine.
Après redémarrage de la machine, on liste les disques :
$ fdisk -l
Disk /dev/vda: 10.7 GB, 10737418240 bytes
16 heads, 63 sectors/track, 20805 cylinders, total 20971520 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000
Device Boot Start End Blocks Id System
/dev/vda1 2048 20971519 10484736 fd Linux RAID autodetect
Disk /dev/vdb: 10.7 GB, 10737418240 bytes
16 heads, 63 sectors/track, 20805 cylinders, total 20971520 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000
Disk /dev/vdb doesn't contain a valid partition table
Disk /dev/md127: 10.7 GB, 10727849984 bytes
2 heads, 4 sectors/track, 2619104 cylinders, total 20952832 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000
Disk /dev/md127 doesn't contain a valid partition table
Mon nouveau disque /dev/vdb apparait bien dans la liste.
Il faut maintenant recopier la table de partition du disque sain /dev/vda vers le nouveau disque /dev/vdb.
$ sfdisk --dump /dev/vda | sfdisk /dev/vdb
Puis on vérifie que l'opération s'est bien déroulée :
$ fdisk -l
Disk /dev/vda: 10.7 GB, 10737418240 bytes
16 heads, 63 sectors/track, 20805 cylinders, total 20971520 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000
Device Boot Start End Blocks Id System
/dev/vda1 2048 20971519 10484736 fd Linux RAID autodetect
Disk /dev/vdb: 10.7 GB, 10737418240 bytes
16 heads, 63 sectors/track, 20805 cylinders, total 20971520 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000
Device Boot Start End Blocks Id System
/dev/vdb1 2048 20971519 10484736 fd Linux RAID autodetect
Disk /dev/md127: 10.7 GB, 10727849984 bytes
2 heads, 4 sectors/track, 2619104 cylinders, total 20952832 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000
Disk /dev/md127 doesn't contain a valid partition table
Mon nouveau disque /dev/vdb contient bien désormais une partition du type Linux RAID autodetect /dev/vdb1.
Pour terminer, il faut maintenant ajouter notre nouvelle partition /dev/vdb1 à notre volume RAID1 /dev/md127 :
$ mdadm /dev/md127 -a /dev/vdb1
Reste à vérifier la reconstruction du RAID :
$ cat /proc/mdstat
Personalities : [raid1] [linear] [multipath] [raid0] [raid6] [raid5] [raid4] [raid10]
md127 : active raid1 vdb1[3] vda1[2]
10476416 blocks super 1.2 [2/1] [U_]
[>....................] recovery = 2.7% (286656/10476416) finish=13.0min speed=13029K/sec
unused devices: <none>
Pour information, la reconstruction du RAID peut être suivie en temps réel grâce à cette commande :
$ watch -n 1 cat /proc/mdstat
Une fois la reconstruction terminée, on vérifie l'état de notre volume RAID1 /dev/md127 :
$ cat /proc/mdstat
Personalities : [raid1] [linear] [multipath] [raid0] [raid6] [raid5] [raid4] [raid10]
md127 : active raid1 vdb1[3] vda1[2]
10476416 blocks super 1.2 [2/2] [UU]
unused devices: <none>
$ mdadm --detail /dev/md127
/dev/md127:
Version : 1.2
Creation Time : Mon May 20 22:18:07 2013
Raid Level : raid1
Array Size : 10476416 (9.99 GiB 10.73 GB)
Used Dev Size : 10476416 (9.99 GiB 10.73 GB)
Raid Devices : 2
Total Devices : 2
Persistence : Superblock is persistent
Update Time : Tue May 21 13:29:20 2013
State : clean
Active Devices : 2
Working Devices : 2
Failed Devices : 0
Spare Devices : 0
Name : vm-vpn:127 (local to host vm-vpn)
UUID : 6479c625:120e2001:65ef33d1:dfb60c0f
Events : 90
Number Major Minor RaidDevice State
2 253 1 0 active sync /dev/vda1
3 253 17 1 active sync /dev/vdb1
Dans l'exemple suivant, je vais sauvegarder mes données sur le disque /dev/vdc et supprimer mon volume RAID1 /dev/md127 .
$ fdisk -l
Disk /dev/vda: 10.7 GB, 10737418240 bytes
16 heads, 63 sectors/track, 20805 cylinders, total 20971520 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000
Device Boot Start End Blocks Id System
/dev/vda1 2048 20971519 10484736 fd Linux RAID autodetect
Disk /dev/vdb: 10.7 GB, 10737418240 bytes
16 heads, 63 sectors/track, 20805 cylinders, total 20971520 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000
Device Boot Start End Blocks Id System
/dev/vdb1 2048 20971519 10484736 fd Linux RAID autodetect
Disk /dev/vdc: 10.7 GB, 10737418240 bytes
16 heads, 63 sectors/track, 20805 cylinders, total 20971520 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000
Disk /dev/vdc doesn't contain a valid partition table
Disk /dev/md127: 10.7 GB, 10727849984 bytes
2 heads, 4 sectors/track, 2619104 cylinders, total 20952832 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000
Disk /dev/md127 doesn't contain a valid partition table
Création d'une partition du type ext4 sur le disque /dev/vdc :
$ fdisk /dev/vdc
$ fdisk -l /dev/vdc
Disk /dev/vdc: 10.7 GB, 10737418240 bytes
2 heads, 17 sectors/track, 616809 cylinders, total 20971520 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0xb4e1f868
Device Boot Start End Blocks Id System
/dev/vdc1 2048 20971519 10484736 83 Linux
Montage de la partition /dev/vdc1 dans le répertoire /mnt
$ mount /dev/vdc1 /mnt
Puis sauvegarde des données (mon volume /dev/md127 est monté dans le répertoire /media/raid)
$ rsync -av /media/raid/ /mnt/
Il faut ensuite démonter le volume RAID1 /dev/md127
$ umount /media/raid
Arrêt du volume /dev/md127 :
$ mdadm --stop /dev/md127
mdadm: stopped /dev/md127
On supprime le volume /dev/md127 :
$ mdadm --remove /dev/md127
On supprime toutes les informations présentes sur les partitions /dev/vda1 et /dev/vdb1
$ mdadm --zero-superblock /dev/vd[ab]1
Pour terminer, éditer le fichier /etc/mdadm/mdadm.conf et supprimer la ligne concernant le volume RAID1 /dev/md127
Ne pas oublier également de supprimer le point de montage du volume RAID1 /dev/md127 dans le fichier /etc/fstab.
Tout dépend du niveau de sécurité configuré pour SELinux.
Il existe 3 modes différents:
- enforcing
- permissive
- disabled
Dans le cas des 2 derniers (permissive & disabled) il ne devrait pas y avoir de problème pour activer et démarrer un nouveau service systemd.
Par contre, si le mode est enforcing, il y a de grandes chances pour que cela empêche le démarrage d'un nouveau service.
Pour le vérifier:
$ sestatus
SELinux status: enabled
SELinuxfs mount: /sys/fs/selinux
SELinux root directory: /etc/selinux
Loaded policy name: targeted
Current mode: enforcing
Mode from config file: enforcing
Policy MLS status: enabled
Policy deny_unknown status: allowed
Memory protection checking: actual (secure)
Max kernel policy version: 33
Donc, si le mode SELinux est enforcing et que vous avez créé un nouveau service et que celui-ci n'arrive pas à démarrer, suivre la procédure ci-dessous.
Exemple avec une distribution AlmaLinux:
Installer le paquet policycoreutils-python-utils.noarch
$ sudo dnf install -y policycoreutils-python-utils.noarch
Exécuter les 2 commandes suivantes:
$ sudo ausearch -m avc -ts today | audit2allow -M le_nom_de_mon_service
$ sudo semodule -i le_nom_de_mon_service.pp
En théorie, l'exécution de la première commande indique d'exécuter la seconde commande.
Modifier le terme le_nom_de_mon_service
Et enfin:
$ sudo systemctl start le_nom_de_mon_service.service
$ sudo systemctl status le_nom_de_mon_service.service
Le problème devrait être réglé.
Récapitulatifs des différentes manières de supprimer les retours à la ligne dans une chaine de caractères.
$ A=$(echo -e "Ceci est une chaine\navec des retours\nà la ligne.")
$ echo "$A"
Ceci est une chaine
avec des retours
à la ligne.
Suppression du retour à la ligne :
$ tr -d "\n" <<< "$A"
Ceci est une chaineavec des retoursà la ligne.
Remplacement du retour à la ligne par un espace :
$ tr "\n" " " <<< "$A"
Ceci est une chaine avec des retours à la ligne.
Suppression du retour à la ligne :
$ sed ':a;N;$!ba;s/\n//g' <<< "$A"
Ceci est une chaineavec des retoursà la ligne.
Remplacement du retour à la ligne par un espace :
$ sed ':a;N;$!ba;s/\n/ /g' <<< "$A"
Ceci est une chaine avec des retours à la ligne.
Suppression du retour à la ligne :
$ while read L; do printf "%s" "$L"; done <<< "$A"
Ceci est une chaineavec des retoursà la ligne.
Remplacement du retour à la ligne par un espace :
$ while read L; do printf "%s" "$L "; done <<< "$A"
Ceci est une chaine avec des retours à la ligne.
Suppression du retour à la ligne :
$ perl -p -e 's/\n//' <<< "$A"
Ceci est une chaineavec des retoursà la ligne.
Remplacement du retour à la ligne par un espace :
$ perl -p -e 's/\n/ /' <<< "$A"
Ceci est une chaine avec des retours à la ligne.
Suppression du retour à la ligne :
$ paste -s -d '' <<< "$A"
Ceci est une chaineavec des retoursà la ligne.
Remplacement du retour à la ligne par un espace :
$ paste -s -d ' ' <<< "$A"
Ceci est une chaine avec des retours à la ligne.
Suppression du retour à la ligne :
$ awk 1 ORS='' <<< "$A"
Ceci est une chaineavec des retoursà la ligne.
Remplacement du retour à la ligne par un espace :
$ awk 1 ORS=' ' <<< "$A"
Ceci est une chaine avec des retours à la ligne.
.
Le changement régulier du password permettant la connexion à son serveur SSH est la garantie d'avoir une haute sécurité.
Le dire, c'est bien mais le faire, c'est mieux.
Le faire tous les combiens de temps ? Que mettre en password ? Vais-je m'en souvenir ?
Voici un petit enchainement de commandes, à enregistrer dans crontab et qui permet de générer aléatoirement un password pour le user désiré grâce à la commande pwgen, de le modifier automatiquement grâce à la commande chpasswd puis de l'envoyer par mail.
$ passwd="user1:`/usr/bin/pwgen -s -y -c 14 1`" && /bin/echo $passwd | /usr/sbin/chpasswd && /bin/echo $passwd | /usr/bin/mail -s "Il fait beau aujourd\'hui" user1@domaine.fr && passwd=""
Pour installer la commande pwgen (par défaut sur Ubuntu) :
$ apt-get install pwgen
Détail de la commande pwgen :
-s : génère des mots de passe complètement aléatoires
-y : insère au moins 1 caractère spécial
-c : insère au moins 1 lettre majuscule
Le nombre 14 indique que l'on veut générer un mot de passe de 14 caractères
Le chiffre 1 indique que l'on veut générer 1 seul mot de passe
L'envoi par mail peut être remplacé par un envoi par sms grâce à la commande gammu.
Pour récupérer les données sur un disque ayant des secteurs défectueux, il est possible d'utiliser la commande dd comme ceci.
L'opération doit être effectuée sur un disque ou une partition non montée.
Première méthode :
On recopie les données de disque à disque.
if=/dev/hdx : correspond au disque source (défectueux)
of=/dev/hdy : correspond au disque cible
Attention à ne pas inverser le if et le of
if pour input (entrée)
of pour output (sortie)
$ dd bs=4k if=/dev/hdx of=/dev/hdy conv=noerror,sync
L'exemple ci-dessus utilise des disques entiers mais il est possible d'effectuer l'opération sur des partitions.
Seconde méthode :
On recopie les données du disque vers un fichier.
$ dd bs=4k if=/dev/hdx of=/path/to/image conv=noerror,sync
Idem avec des partitions.
Je me suis acheté une enceinte bluetooth JBL Flip 5 et quand je l'ai connecté sur mon portable équipé de Ubuntu 20, grosse déception, aucun son, le néant.
Alors que sur mon smartphone, aucun problème.
Une petite recherche sur internet m'a permis de trouver la solution ci-dessous:
$ sudo apt-get install pavucontrol
Formidable, problème réglé....
Un bastion SSH, qu'est-ce que c'est que ce truc là ?
Dans le cadre d'une grappe de serveurs devant être administrés à distance, un bastion SSH est un serveur sur lequel un serveur SSH (openssh-server par exemple) est installé et par lequel on peut accèder en SSH aux autres serveurs.
Le but est d'utiliser ce serveur comme serveur de rebond afin d'accéder aux différents serveurs.
Dans un premier temps, il est nécessaire de créer un nouveau serveur sur lequel nous installerons un serveur SSH.
Pour l'exemple, je vais créer un nouveau serveur avec OpensSUSE 15.5 et installer openssh-server.
Une machine virtuelle sous Proxmox équipée d'un CPU, de 8 Go de disque et 512 Mo de mémoire vive suffira amplement.
Faire en sorte que ce serveur et seulement ce serveur soit accessible, de l'extérieur, via le port SSH 22 (ou autre si vous souhaitez sécuriser encore plus l'accès au bastion SSH).
# zypper in openssh-server
Pour la configuration du serveur SSH, quelques lignes suffisent.
# cat /etc/ssh/sshd_config
PermitRootLogin no
PubkeyAuthentication yes
PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM no
AuthorizedKeysFile .ssh/authorized_keys
PrintMotd no
Subsystem sftp /usr/lib/ssh/sftp-server
AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
AcceptEnv LC_IDENTIFICATION LC_ALL
AllowUsers toto
Quelques petites explications:
Ligne 1, on interdit la connexion avec le compte "root"
Ligne 2, on autorise la connexion à l'aide d'une clé SSH
Ligne 3, 4 et 5, on interdit l'authentification par mot de passe
Ligne 6, permet d'indiquer le fichier contenant les clés autorisées à se connecter
Ligne 7, on désactive l'affichage du contenu du fichier /etc/motd
Ligne 8 à 11, divers paramètres
Ligne 12, permet d'indiquer le ou les utilisateurs autorisés à se connecter
Ensuite, il est nécessaire de créer l'utilisateur avec lequel on se connectera au serveur SSH.
L'important est de créer un utiilisateur n'ayant aucun droit de se connecter au serveur SSH servant de bastion.
# useradd -m -s /bin/false toto
Sur le serveur client, ou n'importe quel autre serveur, créer un clé ssh qui sera utilisée pour se connecter au bastion SSH.
Voir un exemple ici https://isbeta.fr/LsUB2 (créer une clé SSH avec ou sans protection par mot de passe, à vous de choisir)
Pour la suite des opérations, je vais partir du principe que la clé ssh permettant de se connecter au bastion SSH se nommera id_rsa.toto et la clé publique id_rsa.toto.pub
Ensuite, il est nécessaire de copier la clé publique (celle créée ci-dessus id_rsa.toto.pub) dans le fichier authorized_keys du bastion SSH.
Créer le dossier .ssh dans le dossier de l'utilisateur toto du bastion SSH.
# mkdir /home/toto/.ssh
# chown toto /home/toto/.ssh
# chmod 0700 /home/toto/.ssh
Créer ensuite le fichier authorized_keys et y copier la clé publique
# touch /home/toto/.ssh/authorized_keys
# vim /home/toto/.ssh/authorized_keys
# cat /home/toto/.ssh/authorized_keys
ssh-rsa xxxx...lgjgdlkffgjdlkg=
# chown toto /home/toto/.ssh/authorized_keys
# chmod 0600 /home/toto/.ssh/authorized_keys
En théorie, la configuration du bastion SSH est terminée.
Le serveur SSH a été paramétré, le user "toto" autorisé à se connecter a été créé et la clé SSH a été renseignée dans le fichier .ssh/authorized_keys du user "toto".
Maintenant, coté client, il est nécessaire de configurer l'accès au bastion SSH.
Modifier le fichier .ssh/config du client.
# cat .ssh/config
Host monbastion.loc
Hostname monbastion.loc
User toto
Port 22
TCPKeepAlive yes
IdentityFile ~/.ssh/id_rsa.toto
Host mon_serveur_nginx
Hostname 192.168.1.50
User root
Port 22
TCPKeepAlive yes
ProxyJump monbastion.loc
IdentityFile ~/.ssh/id_rsa
Host mon_serveur_mariadb
Hostname 192.168.1.60
User root
Port 22
TCPKeepAlive yes
ProxyJump monbastion.loc
IdentityFile ~/.ssh/id_rsa
Quelques explications:
Le premier host correspond au bastion SSH accessible via internet, rien de bien compliqué, excepté peut-être le paramètre IdentityFile faisant référence à la clé SSH id_rsa.toto, l'unique clé autorisée à se connecter au bastion SSH avec le user toto.
Le second host, est celui qui correspond, pour l'exemple, à mon serveur nginx, inaccessible via internet en SSH, seulement en HTTP et HTTPS.
Pour pouvoir y acccéder, j'indique via le paramètre ProxyJump, d'utiliser le host monbastion.loc pour pouvoir y accéder en SSH. Le paramètre IdentityFile permet d'indiquer une autre clé SSH autorisée à se connecter au serveur nginx.
Idem pour le troisième host.
Les adresses IP indiquées pour les hosts 2 et 3 doivent être accessible via le bastion SSH.
Il est possible de renseigner différents serveurs utilisant le bastion SSH commme serveur de rebond.
Et voilà, la configuration est enfin terminée.
Pour se connecter au serveur nginx, par exemple:
# ssh mon_serveur_nginx
C'est tout simple, la connexion via monbastion.loc est complètement transparente.
Mon dash (tableau de bord) est planté.
Les applications ne sont plus affichées.
Résultat, je ne peux plus lancer mes applications via le dash. C'est vraiment pas très pratique.
Pour corriger les anomalies du dash, une seule chose à faire. Le restaurer.
Pour cela, il suffit juste de supprimer le fichier ~/.local/share/zeitgeist/activity.sqlite
$ cp -a ~/.local/share/zeitgeist/activity.sqlite ~/
$ rm ~/.local/share/zeitgeist/activity.sqlite
Bien entendu, avant toute suppression, on le sauvegarde. Juste au cas où.
Prudence est mère de sûreté.
On redémarre la machine et normalement, tout est rentré dans l'ordre.
Enfin, j'espère ;o)
J'en ai rêvé, Harel Ben-Attia l'a fait.
Utiliser des fichiers texte comme des tables SQL.
C'est ce que propose de faire la commande q.
Ce programme est développé en python.
Pour fonctionner, il utilise donc python 2.4 (minimum) et le module sqlite3.
Il est possible d'utiliser des fichiers texte dont le séparateur de colonne (par défaut) est l'espace.
N'importe quel autre séparateur est utilisable à condition de l'indiquer à l'aide de l'option -d
Si le fichier texte contient une ligne d'en-tête, il est possible de l'indiquer à l'aide de l'option -H et cela permet d'utiliser les en-têtes comme nom de colonne dans les requêtes SQL.
L'option -z permet d'utiliser des fichiers compressés avec gzip.
Le projet est disponible ici.
Un paquet RPM est disponible pour l'installation.
Pour les distributions Debian/Ubuntu, utiliser le programme alien pour convertir le paquet RPM en DEB.
Pour l'installtion, sous Debian/Ubuntu, après conversion du paquet :
$ dpkg --install q_xxx_all.deb
Les différentes utilisations possibles :
Utiliser la commande q derrière un pipe
Par exemple, la commande ls -l retourne le contenu d'un répertoire structuré en colonne.
Par conséquent, du fait que le retour de cette commande soit structuré, il est possible de l'envoyer à la commande q via un pipe et d'y effectuer des petites requêtes SQL.
$ ls -l /var/log
-rw-r--r-- 1 root root 3554 Mar 12 14:09 alternatives.log
-rw-r--r-- 1 root root 1208 Feb 21 10:51 alternatives.log.1
-rw-r--r-- 1 root root 246 Jan 27 18:17 alternatives.log.2.gz
-rw-r--r-- 1 root root 385 Jan 6 21:10 alternatives.log.3.gz
-rw-r--r-- 1 root root 539 Nov 22 08:16 alternatives.log.4.gz
-rw-r--r-- 1 root root 276 Oct 24 16:47 alternatives.log.5.gz
-rw-r--r-- 1 root root 948 Sep 23 22:35 alternatives.log.6.gz
drwxr-xr-x 2 root root 4096 Mar 1 05:00 apt
-rw-r----- 1 syslog adm 370529 Mar 12 14:16 auth.log
Envoyer un mail via la commande telnet permet de tester la configuration d'un serveur SMTP.
En rouge, les informations à saisir.
$ telnet smtp.free.fr 25
Trying 212.27.48.4...
Connected to smtp.free.fr.
Escape character is '^]'.
220 smtp4-g21.free.fr ESMTP Postfix
HELO test.domain.com
250 smtp4-g21.free.fr
MAIL FROM:<test@domain.com>
250 2.1.0 Ok
RCPT TO:<toto@domain.fr>
250 2.1.5 Ok
DATA
354 End data with <CR><LF>.<CR><LF>
Subject: test message
This is the body of the message!
.
250 2.0.0 Ok: queued as 2D8FD4C80FF
quit
221 2.0.0 Bye
Connection closed by foreign host.
Explications :
Si une authentification est nécessaire, après avoir envoyé la commande HELO, il suffit d'envoyer la commande AUTH LOGIN (après le point 4).
Le serveur répond en affichant "334 VXNlcm5hbWU6".
Cette chaine est encodée en base64.
Traduction en langage humain : "334 Username:"
Il suffit donc de répondre en renseignant son username encodé, bien sûr, en base64.
Le serveur répond ensuite en affichant "334 UGFzc3dvcmQ6".
Cette chaine est également encodée en base64.
Traduction en langage humain : "334 Password:"
Il suffit donc de répondre en renseignant son password encodé, également, en base64.
Si tout se passe bien, le serveur doit répondre "235 Authentication successful"
Reste à continuer la procédure à partir du point 5.
Pour l'encodage en base64, toutes les infos ici.
Pour utiliser un serveur FTP dans un script, il faut que l'identification se fasse également via le script.
Par contre, la sécurité du serveur FTP est diminuée du fait d'avoir en clair dans le script les identifiants de connexion.
Cette méthode est donc à utiliser avec des serveurs FTP ne contenant pas de données sensibles.
L'exemple suivant permet de télécharger du serveur ftp "ftp.tutu.fr" le fichier "fichier.txt" en utilisant l'identifiant "toto" et le mot de passe "tata"
#!/bin/bash
loginftp="toto"
motdepassftp="tata"
host_ftp="ftp.tutu.fr"
mon_fichier="fichier.txt"
# On se positionne dans le dossier /tmp
# où sera téléchargé le fichier du serveur FTP
cd /tmp
ftp -in <<EOF
open $host_ftp
user $loginftp $motdepassftp
get $mon_fichier
close
bye
EOF
# Je peux ensuite exécuter d'autres commandes
# sur le fichier téléchargé
exit 0
Il ne reste plus qu'à automatiser le script avec une tâche cron.
La commande watch permet d'exécuter à intervalle régulière n'importe quelle commande passée en paramètre.
La période de rafraichissement par défaut est de 2 secondes.
L'option -n permet d'indiquer une période de rafraichissement en secondes.
L'option -d permet de mettre en surbrillance les différences survenues entre 2 périodes de rafraichissement.
Surveiller le contenu d'un répertoire :
$ watch -d ls -l /tmp
Cette commande affiche à l'écran le contenu du répertoire /tmp et raffraichit l'affichage toutes les 2 secondes en mettant les différences en surbrillance (option -d).
Dès qu'un fichier/répertoire est créé/modifié/supprimé l'information apparait à l'écran.
Idem mais toutes les 10 secondes :
$ watch -n 10 -d ls -l /tmp
Surveiller la reconstruction d'un volume RAID :
$ watch cat /proc/mdstat
Surveiller les connexions et l'utilisation d'un serveur :
$ watch -d w
$ watch -d uptime
Qu'est ce que Windigo ?
Windigo est un "virus" infectant les serveurs UNIX (entre autres) et qui utilise ces derniers pour envoyer des spams en grosse quantité.
Pour que le virus soit actif, une backdoor OpenSSH dénommée "Ebury" doit être installée manuellement sur les serveurs par les hackers.
Pour vérifier l'infection du système, il est nécessaire d'exécuter la commande suivante :
$ ssh -G 2>&1 | grep -e illegal -e unknown > /dev/null && echo "System clean" || echo "System infected"
Cette commande peut paraitre compliquée alors qu'elle est, au contraire, toute simple.
Que fait-elle exactement ?
Si le système est infecté, la backdoor OpenSSH utilise l'option -G de la commande ssh qui normalement n'existe pas si le système est sain.
Pour faire simple, il suffit donc d'exécuter la commande ssh avec cette fameuse option (-G) pour voir si le système est compromis.
$ ssh -G
ssh: illegal option -- G
Si la commande retourne une erreur, comme celle indiquée ci-dessus, c'est que le système est sain.
A l'inverse, si aucune erreur n'est retournée par la commande, c'est que le système est compromis et qu'il faut donc, rapidement, y remédier.
Pour cela, il est nécessaire de formater le serveur et d'y réinstaller un système complet.
Il faut également changer tous les mots de passe et clés privées.
Utiliser des applications graphiques d'un serveur (Ubuntu/Debian/CentOS) sur un poste Windows via une connexion SSH.
Pré-requis coté server :
$ sudo apt-get install openssh-server
$ sudo apt-get install xvfb xdm xfonts-base
$ sudo apt-get install twm "xfonts-100dpi*" xterm
Activer X11Forwarding dans la configuration du serveur SSH distant:
# cat /etc/ssh/sshd_config | grep X11
X11Forwarding yes
Pré-requis coté client (Windows par exemple) :
Mise en oeuvre :
Ouvrir Xming
Ouvrir Putty
Saisir l'adresse IP du serveur
Dans "Connexion" --> "SSH" --> "X11", cocher "Enable X11 forwarding"
Ciquer sur "OPEN"
Dans la console Putty, saisir "Login" et "Password"
Pour ouvrir une console par exemple saisir :
$ xterm &
La variable $DISPLAY permet de vérifier que le X11Forwarding est bien activé:
# echo $DISPLAY
localhost:10.0
La commande xauth list permet d'afficher le magic cookie indispensable au X11Forwarding :
# xauth list
monServeur/unix:10 MIT-MAGIC-COOKIE-1 17e3926a07573d0c51be57158896cf4c
Conserver le X11Forwarding et le magic cookie après avoir changé d'utilisateur:
Dans le cas où vous auriez besoin de lancer une application avec un utilisateur différent de celui utilisé pour la connexion SSH, il faut obligatoirement transmettre au nouvel utilisateur le magic cookie.
Utiliser la commande précédente pour afficher le magic cookie (xauth list):
Changer d'utilisateur et ajouter le magic cookie à l'aide de la commande xauth add et en paramètre, le résultat de la commande xauth list:
# su - user1
$ xauth add monServeur/unix:10 MIT-MAGIC-COOKIE-1 17e3926a07573d0c51be57158896cf4c
gocr est une commande qui permet de faire de la reconnaissance de caractères sous GNU/Linux.
Elle utilise des fichiers au format pnm.
Pré requis :
Pour utiliser gocr, il est nécessaire d'installer le programme djpeg qui permet de convertir un fichier jpeg en pnm.
$ sudo apt-get install gocr libjpeg-progs
Utilisation :
Je vais partir du cas le plus complet c'est à dire effectuer une reconnaissance de caractères à partir d'un fichier PDF (une facture par exemple).
Je dois donc convertir ce fichier PDF en fichier PNM.
Je vais utiliser la commande convert qui permet de convertir un fichier PDF en JPEG, puis la commande djpeg pour convertir mon fichier JPEG en PNM.
Il faut que le fichier JPEG généré à partir du fichier PDF soit d'une excellente qualité ( -density 500).
$ convert -density 500 exempleFactureMicroRemise.pdf exempleFactureMicroRemise.jpg
Pour finir, conversion du fichier JPEG en PNM avec la commande djpeg puis envoi du résulat à la commande gocr qui va écrire le contenu dans un fichier texte.
$ djpeg -pnm -gray exempleFactureMicroRemise.jpg | gocr - > exempleFactureMicroRemise.txt
Le résultat obtenu est assez satisfaisant.
jigl est un programme qui permet de générer une gallerie photo HTML à partir d'images se trouvant dans un répertoire.
Un petit exemple de ce qu'il est possible de faire avec jigl.
Installation :
$ apt-get install jigl
Générer sa première gallerie :
1 - Copier toutes les images dans un répertoire (dans l'exemple suivant les images se trouvent dans le répertoire "testJigl").
2 - Générer la gallerie en exécutant la commande suivante :
$ jigl testJigl
Une fois l'opération terminée, 3 répertoires ont été créés dans le répertoire "testJigl"
testJigl/slides
testJigl/thumbs
testJigl/web
C'est dans le répertoire "web" que se trouvent la gallerie HTML.
2 pages HTML ont été créées par images ainsi qu'un page "index.html".
Il est possible d'ajouter des options afin de personnaliser sa gallerie, comme par exemple :
- Spécifier le titre de la page index.html avec l'option --index-title "Mon Titre"
- Spécifier le nombre de lignes affichées sur la page index.html avec l'option --index-row 5 (permet d'afficher 5 lignes).
- Spécifier le thème à utiliser avec l'option --theme nomDuTheme (black, jovotek, white)
- Spécifier le répertoire web de destination avec l'option --web-dir nomDuRepertoire
Plus d'info avec :
$ jigl --help
Pixelize est une application permettant de pixeliser une image en utilisant d'autres images référencées dans sa base de données.
Pré-requis
Installer l'application pixelize
$ apt-get install pixelize
Configuration
Avant d'utiliser pixelize, il est nécessaire de mettre à jour sa base de données. Il s'agit d'un fichier nommé pic_db.dat situé dans le répertoire home (~/pic_db.dat).
Pour le mettre à jour, rien de plus simple. Il suffit d'utiliser l'utilitaire make_db de pixelize.
Pixelize reconnait les formats d'images les plus courants.
Pour mettre à jour la base de données avec le contenu d'un répertoire contenant des images :
$ make_db /mon_repertoire/*.jpg
Ou pour mettre à jour la base de données avec des images se trouvant dans un ensemble de sous-répertoires :
$ find /mon_repertoire -iname "*.jpg" -print | xargs make_db
Plus il y aura d'images référencées dans la base de données, meilleure sera la pixelisation.
Utilisation
Pour utiliser pixelize, il est recommandé de lancer l'application à partir d'un terminal
$ pixelize
De cette manière, en cas d'erreur, celles-ci s'afficheront dans le terminal.
Pour pixeliser une image, utiliser le menu "File => Open" puis sélectionner l'image souhaitée.
Pour lancer la pixelisation cliquer sur "Options => Render"
Le temps de pixelisation est fonction de la taille de la photo à pixeliser et de la quantité d'images référencées dans sa base de données.
Pour sauvegarder l'image pixelisée, cliquer sur "File => Save". Il faut obligatoirement indiquer l'extension du fichier (jpeg, bmp, png ...)
Exemple
Image d'origine
Pixelisation effectuée avec une base de 400 photos
Pixelisation effectuée avec une base de 11 000 photos
Sur les systèmes Debian et dérivés, pour corriger l'erreur
syslog-ng: Error setting capabilities, capability management disabled; error='Operation not permitted'
il suffit de décommenter la ligne SYSLOGNG_OPTS="--no-caps" dans le fichier /etc/default/syslog-ng.
$ cat /etc/default/syslog-ng
# If a variable is not set here, then the corresponding
# parameter will not be changed.
# If a variables is set, then every invocation of
# syslog-ng's init script will set them using dmesg.
# log level of messages which should go to console
# see syslog(3) for details
#
#CONSOLE_LOG_LEVEL=1
# Command line options to syslog-ng
SYSLOGNG_OPTS="--no-caps"
On relance syslog-ng
$ service syslog-ng restart