FAQ LinuxConsultez toutes les FAQ
Nombre d'auteurs : 56, nombre de questions : 260, dernière mise à jour : 27 juin 2022 Ajouter une question
Cette FAQ a été réalisée à partir des contributions des membres du forum Linux de Developpez.com et de l'équipe de rédaction. Merci à eux !
Nous sommes perpétuellement à l'écoute de vos suggestions et corrections, n'hésitez pas à nous en faire part sur le forum.
- Comment connaître les différents processus en cours lancés par un programme ?
- Que signifie le caractère > ou < (redirection) ? Quelle utilité ?
- Que signifie le caractère | (pipe) ? Quelle utilité ?
- Que signifie le sticky bit ?
- Comment filtrer la sortie standard et/ou la sortie d'erreurs ou encore un fichier ?
- Comment effacer des fichiers selon leur date ?
- Que signifie le caractère & ? A quoi sert-il ?
- Comment passer un processus en background si on a oublié le & ?
- Comment dialoguer avec un serveur ftp ?
- Démarrer un programme non-graphique en arrière-plan et le rappeler à la volée ?
- Comment récupérer les 10 derniers caractères d'une chaine ?
- Comment faire une boucle sur un indice/incrément ?
- Quelle est la différence entre nohup et & ?
- Comment lire/parcourir un fichier ?
- Quelles sont les différentes redirections possibles pour les sorties standard et d'erreur ?
- Pourquoi faut-il éviter d'utiliser la boucle for sur une sortie de commande ?
- Pourquoi faut-il éviter la commande ls dans les scripts ?
- Comment trouver les fichiers contenant une chaine de caractères et afficher les lignes concernées ?
- Pourquoi faut-il encadrer les variables par des doubles quotes avec la commande test ?
- Comment supprimer des fichiers objets et fichiers temporaires automatiquement ?
- Comment demander des informations à l'utilisateur dans un script ?
- Comment afficher plusieurs lignes autour des résultats de grep ?
Par exemple, vous utilisez le Shell zsh, et vous voulez savoir à quel(s) PID (Processus IDentification) il(s) est(sont) lié(s).
La commande fuser retourne les différents PID de zsh :
Code bash : | Sélectionner tout |
1 2 | $ fuser /bin/zsh /bin/zsh: 1942e 2860e 2996e 3469m 3487e 4527m 4607e |
Comme indiqué dans le man, les caractères suivant le PID correspondent à : On observe donc ici que l'on a cinq programmes zsh en cours d'exécution, et deux projetés en mémoire.
On vérifie la valeur des PID qui correspond bien aux valeurs retournées par fuser :
- c : répertoire courant ;
- e : programme en cours d'exécution ;
- f : fichier ouvert. f est omis par défaut ;
- r : répertoire racine ;
- m : fichier projeté en mémoire, ou bibliothèque partagée.
Code bash : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 | $ ps -aux | grep zsh francois 1942 0.0 0.0 3560 4 vc/1 S 10:24 0:00 -zsh francois 2860 0.0 0.9 3900 2484 pts/1 S 13:43 0:00 /bin/zsh francois 2996 0.0 0.8 3692 2212 pts/2 S 14:01 0:00 /bin/zsh root 3469 0.0 0.8 3612 2084 pts/1 S 15:25 0:00 zsh francois 3487 0.0 1.0 3976 2580 pts/1 S 15:25 0:00 zsh root 4527 0.0 0.9 3768 2308 pts/2 S 19:49 0:00 zsh francois 4607 0.2 0.8 3728 2268 pts/2 R 20:13 0:00 zsh francois 4632 0.0 0.2 1904 760 pts/2 R 20:14 0:00 grep zsh |
Une autre alternative est d'utiliser la commande ps de la manière suivante :
Code bash : | Sélectionner tout |
$ ps -ef | grep zsh
Ici les options POSIX sont privilégiées rendant ainsi cette syntaxe portable sur l'ensemble des UNIX.
Ce sont les opérateurs permettant de gérer les flux de données.
La redirection ">" permet de stocker la sortie d'un programme dans un fichier. Cela crée le fichier s'il n'existait pas, et efface son contenu s'il existe (il faut donc faire attention !) :
Code bash : | Sélectionner tout |
$ cat fichier1 > fichier_sauvegarde
Si l'on veut rajouter des données au fichier, on utilisera la double redirection ">>" :
Code bash : | Sélectionner tout |
$ cat ajout >> fichier_sauvegarde
La redirection "<" joue le même rôle. Au lieu de taper au clavier le contenu du fichier, vous pouvez utiliser cette redirection et ainsi le fichier va se substituer a l'entrée standard (saisie clavier) :
Code bash : | Sélectionner tout |
1 2 | $ cat < nom_du_fichier $ cat < fichier1 > fichier_sauvegarde |
Vous remarquerez que la dernière commande a le même effet que la première.
Le caractère "|" permet de lier des commandes entre elles. La sortie standard d'une commande devient l'entrée standard de la commande suivante :
Code bash : | Sélectionner tout |
$ cat fichier | grep YES
La commande cat envoie le contenu du fichier vers la commande grep qui va le lire. Bien entendu, si vous utilisez une commande qui ne lit pas de données sur l'entrée standard, cela n'aura aucun résultat :
Code bash : | Sélectionner tout |
$ cat fichier | ls
La commande cat envoie bien le contenu vers la commande ls, laquelle ne lit pas sur son entrée standard. Par conséquent, le pipe entre les deux commandes ne sert absolument à rien .
Il est tout à fait possible d'enchaîner un très grand nombre de pipes (la limite dépend des Shells).
Code bash : | Sélectionner tout |
$ cat fichier | grep YES | sed 's/YES/NO/'
Voici la signification du sticky bit :
- sur un fichier : un programme exécutable sera maintenu en zone de swap après la fin de son exécution, ce qui accélérera les chargements ultérieurs ;
- sur un répertoire : un fichier du répertoire ne peut être supprimé que par son propriétaire.
Permettre à n'importe quel utilisateur de créer et modifier ses fichiers dans un répertoire, c'est mettre les droits rw (et x pour l'exploration) pour tous les utilisateurs (propriétaire, groupe et autres).
Le stickybit sert juste à éviter qu'un utilisateur ne détruise les fichiers des autres. On le fixe de la manière suivante :
Pour le mettre :
Code bash : | Sélectionner tout |
chmod a+t
Pour l'enlever :
Code bash : | Sélectionner tout |
chmod a-t
C'est aussi le 1 de la première position lorsque l'on utiliser un masque à quatre chiffres avec la notation octale de chmod.
À l'aide des commandes grep et cut, on va extraire l'occurrence "/home/francois" du fichier /etc/passwd :
Code bash : | Sélectionner tout |
1 2 | $ cat /etc/passwd | grep francois francois:x:502:502::/home/francois:/bin/zsh |
La commande grep permet de ne conserver que la ligne contenant "francois" de la sortie standard de cat. Il est toutefois possible de parser directement le fichier avec grep :
Code bash : | Sélectionner tout |
$ grep "francois" /etc/passwd
Code bash : | Sélectionner tout |
1 2 | $ grep "francois" /etc/passwd | cut -f6 -d: /home/francois |
La commande cut permet de couper certains mots d'une ligne.
L'option -f6 indique que l'on veut garder la 6e chaîne de caractères, délimitée par le signe ":" (option - d).
Il est également possible d'utiliser le langage awk (avec l'interpréteur gawk par défaut sous Linux) pour faire des découpages similaires voire plus complexes avec des expressions régulières en guise de séparateurs notamment.
Exemple équivalent avec awk :
Code bash : | Sélectionner tout |
awk -F ":" '($0 ~ "francois"){print $6}' /etc/passwd
Vous remarquerez que dans cet exemple, on a pu également se passer de la commande grep.
La commande find permet de faire le plus rapidement possible ce genre de traitement.
Pour afficher les fichiers vieux de plus de 24 heures :
Code bash : | Sélectionner tout |
$ find . -ctime +1
Pour les effacer :
Code bash : | Sélectionner tout |
$ find . -ctime +1 -exec rm -f \{\} \;
L'option -i de la commande rm est utilisée pour demander une confirmation pour chaque fichier à effacer.
Ce caractère signifie que la commande sera exécutée en tâche de fond.
Ainsi vous aurez toujours accès au Shell pour exécuter d'autres commandes sur le terminal :
Code bash : | Sélectionner tout |
$ xmms &
Quand on lance une application depuis le terminal (xpdf, emacs...), on veut souvent reprendre la main sur ce même terminal, non ?
Mais on a oublié le "&" magique ! C'est terrible, il va falloir tout refermer pour tout réouvrir !
Eh bien non : imaginons le cas :
Code bash : | Sélectionner tout |
$ xpdf toto.pdf
Si on veut reprendre la main sans avoir à fermer, on revient sur le terminal, puis un petit Ctrl-Z histoire de geler le processus : là, on reprend la main. Et tout de suite derrière, on fait :
Code bash : | Sélectionner tout |
$ bg
Il existe de nombreux programmes FTP en mode console.
Voici un exemple pour exécuter des commandes FTP automatiquement :
Code bash : | Sélectionner tout |
$ lftp -c "open nom_de_domaine ; user login password ; mput src destination ; ls"
Ou :
Code bash : | Sélectionner tout |
1 2 3 4 | $ ncftp -u login -p passwd host << EOF get fichier ls EOF |
Ces méthodes sont utilisées dans les scripts Shells (par cron notamment).
La commande screen permet de lancer des processus non graphiques, qui seront rattachés au processus init.
Ainsi, vous pourrez enlever votre programme de votre console et le rappelez quand vous le désirez. Pour cela, commençons par créer un screen :
Code bash : | Sélectionner tout |
screen -dmS nom_du_screen 'commande_a_lancer'
Vous entrez directement dans votre screen en lançant la commande. Pour détacher le screen de votre terminal :
Code : | Sélectionner tout |
CTRL+A CTRL+D
Pour attacher le screen à votre terminal :
Code bash : | Sélectionner tout |
screen -x nom_du_screen
Vous pouvez ainsi lancer un bash détachable de votre terminal et récupérable n'importe quand et n'importe où. Très pratique pour ne pas avoir beaucoup de fenêtres ouvertes ou quand on se connecte à distance à une machine de différents postes.
Les raccourcis clavier sont modifiables dans un fichier de configuration /etc/screenrc.
Code bash : | Sélectionner tout |
1 2 3 4 5 | $ toto="bonjour le monde" $ echo ${toto:$((${#toto}-10))} r le monde $ echo ${toto: -10} # version plus simple r le monde |
- ${var:x} : extrait la sous chaîne de $var à partir caractère n° x jusqu'à la fin ;
- $((....)) : permet de faire des calculs.
1) Avec la commande seq :
Code bash : | Sélectionner tout |
1 2 3 | for i in $(seq 1 10); do # traitements itérés avec i allant de 1 à 10 done |
2) Autres solutions en bash :
Code bash : | Sélectionner tout |
1 2 3 4 5 6 7 | for i in (( i=1 ; i<=10 ; i++ )); do # traitements itérés avec i allant de 1 à 10 done for i in {1..10}; do # traitements itérés avec i allant de 1 à 10 done |
Lorsqu'on lance une commande avec le caractère & à la fin, la commande est lancée en tâche de fond mais reste rattachée à votre terminal. Vous pouvez continuer à travailler sur le terminal, mais si vous le quittez, la tâche de fond est détruite (rapport père/fils).
Si vous lancez une commande avec nohup en préfixe (exemple : nohup ma_tache.sh), alors votre tâche est détachée de son père et rattachée à l'init si vous quittez votre terminal...
Pour lire la première ligne d'un fichier uniquement :
Code bash : | Sélectionner tout |
1 2 | read -r premiere_ligne < fichier echo "$premiere_ligne" |
Ici, le contenu de « fichier » est redirigé vers la commande read, qui va placer ce qu'elle a lu dans une variable « $premiere_ligne ».
Pour lire tout le contenu du fichier, il est possible d'utiliser une boucle while :
Code bash : | Sélectionner tout |
1 2 3 | while read -r ligne; do echo "$ligne" done < fichier |
Il est également possible de découper la ligne en autant de variables que nécessaire :
Code bash : | Sélectionner tout |
1 2 3 4 | while read -r colonne1 colonne2 toutLeResteDeLaLigne; do ligneComplete="$colonne1 $colonne2 $toutLeResteDeLaLigne" echo "$ligneComplete" done < fichier |
Si vous avez besoin de découper la ligne en fonction du formatage d'un fichier (CSV par exemple), vous pouvez modifier l'environnement de la commande read en adaptant l'IFS (Internal Field Separator):
Code bash : | Sélectionner tout |
1 2 3 4 | while IFS=';' read -r colonne1 colonne2 toutLeResteDeLaLigne; do ligneComplete="$colonne1;$colonne2;$toutLeResteDeLaLigne" echo "$ligneComplete" done < fichier.csv |
Vous pouvez également utiliser un tableau :
Code bash : | Sélectionner tout |
1 2 3 4 | while IFS=';' read -ra tableau; do ligneComplete="${tableau[@]}" echo "$ligneComplete" done < fichier.csv |
Vous pouvez enfin utiliser des paramètres positionnels :
Code bash : | Sélectionner tout |
1 2 3 4 5 6 | while read -r ligne; do IFS=';' set -- $ligne # éclatement de la ligne en paramètres positionnels echo "première colonne : $1" echo "ligne complète : $@" done < fichier.csv |
Voici une liste non exhaustive de redirections possibles, avec :
- stdout: la sortie standard d'une commande ;
- stderr: la sortie d'erreur d'une commande.
1) Rediriger stderr sur stdout :
Code bash : | Sélectionner tout |
commande 2>&1
Ceci aura pour effet de capturer les deux sorties en une, ce qui peut s'avérer utile si vous redirigez stdout dans un fichier par exemple :
Code bash : | Sélectionner tout |
1 2 3 | $ commande >fichier 2>&1 # ou $ commande 1>fichier 2>&1 |
Dans cet exemple, stdout et stderr seront toutes deux redirigées vers fichier.
2) Capturer uniquement la sortie stdout et éliminer la sortie stderr d'une commande :
Code bash : | Sélectionner tout |
$ commande 2>/dev/null
3) Capturer uniquement la sortie stderr et éliminer la sortie stdout
Code bash : | Sélectionner tout |
$ commande 2>&1 1>/dev/null
4) Éliminer stdout et stderr :
Code bash : | Sélectionner tout |
1 2 3 | $ commande >/dev/null 2>&1 # ou $ commande 1>/dev/null 2>&1 |
5) Fusionner stdout et stderr pour capturer stderr et renvoyer stdout vers l'ancien stderr :
Code bash : | Sélectionner tout |
$ commande 3>&1 1>&2 2>&3 3>&-
6) Capturer les sorties stdout et stderr d'une commande dans des fichiers distincts :
Code bash : | Sélectionner tout |
$ commande [args] 1>commande.out 2>commande.err
7) Rediriger stdout et stderr au même endroit mais en ajoutant le préfixe « Err » aux erreurs :
Code bash : | Sélectionner tout |
$ commande 2> >(sed 's/^/Err : /' >&2)
8) Rediriger stderr vers stdout et ajouter le résultat de stdout dans un fichier tout en continuant de l'afficher sur la sortie standard :
Code bash : | Sélectionner tout |
commande 2>&1 | tee fichier
La boucle for s'effectue sur une liste de valeur :
Code bash : | Sélectionner tout |
1 2 3 | for var in val1 val2 ...; do # ... done |
Par conséquent lorsque vous écrivez :
Code bash : | Sélectionner tout |
1 2 3 | for var in $(commande); do # ... done |
Vous parcourez la sortie de commande « mot par mot » et non « item par item ». Cela peut être source d'erreur notamment lorsqu'un item est composé d'espaces.
Vous trouverez ici des exemples d'erreurs engendrés par cette syntaxe.
Une solution consiste à parcourir la sortie de la commande « ligne par ligne » grâce à cette syntaxe :
Code bash : | Sélectionner tout |
1 2 3 | commande|while read -r; do # la variable $REPLY contient la ligne parcourue done |
D'autres syntaxes sont possibles :
Code bash : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 | while read -r; do # la variable $REPLY contient la ligne parcourue done < <(commande) # ou while read -r; do # la variable $REPLY contient la ligne parcourue done <<< "$(commande)" # les doubles quotes sont importantes ici |
Vous pourrez voir dans ce cours, qu'il y a toujours moyen d'éviter la boucle for sur une sortie de commande.
La commande ls est généralement superflue dans les scripts voire potentiellement génératrice de bogues (dans le cas où on l'utilise avec une boucle for par exemple).
Pour parcourir les fichiers d'un répertoire, il suffit d'utiliser le métacaractère « * » (wildcard) :
Code bash : | Sélectionner tout |
1 2 3 | for fichier in *; do # ... done |
Il est également possible de se servir de la wildcard comme vous le feriez avec les commandes find, ls ou autres :
Code bash : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 | # préciser une extension for fichier in *.log; do # ... done # préciser un chemin de répertoire à parcourir dir="/home/votre_nom/rep" for fichier in "$rep"/*; do # ... done # ... |
Pour récupérer des informations sur un fichier, vous pouvez utiliser la commande stat qui est prévue pour cela. Exemple pour récupérer les droits d'un fichier :
Code bash : | Sélectionner tout |
1 2 3 | stat -c "%A" fichier # au lieu de ls -l fichier|cut -d" " -f1 |
Vous souhaitez trouver dans quels fichiers se trouve la chaine "CHAINE", lister leur chemin (relatif à notre position), et afficher les lignes contenant cette chaine de caractères.
Pour cela, vous pouvez utiliser un grep récursif :
Code bash : | Sélectionner tout |
$ grep -Rn "CHAINE" repertoire/
Avec les couleurs si votre version de grep et votre configuration le permettent :
Code bash : | Sélectionner tout |
$ grep --color -Rn "CHAINE" repertoire/
Il est possible d'utiliser la commande find si on veut effectuer la recherche avec des conditions plus strictes. Dans cet exemple, on recherche les fichiers *.sh dont vous êtes l'utilisateur propriétaire et qui sont exécutables :
Code bash : | Sélectionner tout |
$ find repertoire/ -type f -user nom_user -perm /u+x -name "*.sh" -exec grep --color -Hn "CHAINE" {} 2>/dev/null \;
De manière générale, il faut encadrer les variables par des doubles quotes dans ses scripts, notamment lorsque l'on utilise la commande test ou son fork [ afin d'éviter ce genre d'erreurs.
Ceci ne s'applique pas lorsque l'on utilise la syntaxe Bash des doubles crochets [[ (commande test étendue).
La commande qui va suivre vous permettra de supprimer tous les fichiers dans le dossier courant prototypé de la sorte :
- fichier.extension~
- #fichier.extension#
Code bash : | Sélectionner tout |
find . -name '*~' -print -delete -o -name '#*#' -print -delete
Cela vous permettra de nettoyer vos dossiers.
Pendant l'exécution d'un script, il peut arriver qu'on ait besoin de demander des informations à un utilisateur ; qu'il s'agisse d'une simple confirmation (continuer [Yn] :), ou d'une donnée plus large (quel est le chemin du fichier à traiter), il est question de lire des données depuis l'entrée standard avec la commande read.
Code bash : | Sélectionner tout |
read -p 'continuer [Yn] : '
Le script semble figé, mais, en fait, il attend que l'utilisateur valide le texte qu'il a entré en appuyant sur la touche Enter.
L'invite affichée par l'option -p est envoyée sur la sortie d'erreur.
Cela signifie que lorsque cette dernière est renvoyée vers un fichier journal, l'invite ne sera plus visible.
Il peut alors être préférable d'omettre cette option, et de faire un echo de l'invite sur la sortie standard, bien sûr.
Comme pour lire un fichier ligne par ligne, il est possible de demander à l'utilisateur d'entrer des données sous forme d'un tableau.
Il faut que l'utilisateur respecte un certain format :
Code bash : | Sélectionner tout |
1 2 3 4 5 6 7 | $ read -a tableau 'mlk mlk' poi $ printf '-> %s\n' "${tableau[@]}" -> 'mlk -> mlk' -> poi |
Il faut donc protéger le séparateur par défaut :
Code bash : | Sélectionner tout |
1 2 3 4 5 | $ read -a tableau mlk\ mlk poi $ printf '-> %s\n' "${tableau[@]}" -> mlk mlk -> poi |
On peut définir un séparateur avec l'IFS (Internal Field Separator) :
Code bash : | Sélectionner tout |
1 2 3 4 5 | $ IFS=';' read -a tableau mlk mlk;poi $ printf '-> %s\n' "${tableau[@]}" -> mlk mlk -> poi |
Par défaut, grep retourne uniquement les lignes correspondant à la recherche effectuée. Toutefois, il est aussi possible d'afficher un nombre de lignes avant et après les lignes concernées par la recherche grâce aux options :
- -B NUM : pour afficher NUM lignes avant la ligne concernée ;
- -A NUM : pour afficher NUM lignes après la ligne concernée ;
- -C NUM : pour afficher NUM lignes avant et après la ligne concernée.
Ces lignes autour de la ligne concernée sont appelée le "contexte" du résultat.
Proposer une nouvelle réponse sur la FAQ
Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour çaLes sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2024 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.