Divers astuces en Shell
Posted on 2014-09-07 in Trucs et astuces Last modified on: 2015-02-20
Liste de commandes pour des actions spécifiques. Pas/peu de détails/explications, prérequis de shell supposés connus. Si une commande est donnée pour bash uniquement, cela signifie qu’elle n’est pas compatible avec le shell POSIX ou d’autres implémentations basiques mais est vraisemblablement disponible dans les autres implémentations évoluées telles que zsh.
J'ai initialement publié ce document ici. Ce document se veut un peu plus complet et ne contient pas de rappels de commandes élémentaires comme wc. J'ai également écrit un tutoriel sur le shell.
Sommaire
- Corriger le caractère de fin de ligne
- Enlever les shebang de plusieurs fichiers
- Opérations avancées sur les variables
- Manipulation avancée de chaînes de caractères
- Générer des nombres aléatoires
- Savoir si une chaîne est contenue dans une autre
- Renommer les fichiers en fonction d’une expression régulière
- Savoir si un script est lancé dans un shell interactif
- Chmod a+X
- Différences entre les implémentations de certaines commandes entre GNU et BSD
Corriger le caractère de fin de ligne
Pour changer les caractères de fin de ligne d'un fichier de \r\n (windows) à \n (Unix), (l'option -i fait en sorte que la modification se fasse dans le même fichier).
sed -i 's/\r$//' file
Enlever les shebang de plusieurs fichiers
# Remove shebang for lib in $RPM_BUILD_ROOT/svgwrite/*.py; do sed -i '1{\@^#!/usr/bin/env python@d}' $lib done
Opérations avancées sur les variables
Valeurs par défaut
Il est tout à fait possible de donner une valeur par défaut à une variable en bash. Ainsi, le code suivant : FOO=${FOO:-coucou} signifie que :
- Si la variable FOO est définie, alors ne rien faire
- Si FOO n’est pas définie, alors FOO vaut coucou
Cela fonctionne aussi avec une autre variable : FOO=${toto:-coucou}. Cette fois, FOO prendra la valeur coucou si toto n’est pas définie. Cette forme laisse toto inchangée. Pour affecter coucou a foo et toto : FOO=${toto:=coucou}.
Travailler avec les chemins
Le shell dispose de moyen de travailler avec les chemins de façon facile et agréable :
- Supprimer le dernier / : ${a%/}
- Supprimer le premier / : ${#*/}
- Récupérer le dossier courant : ${a##*/} (si a ne se termine pas par /)
- Récupérer le dossier parent : ${a%/*}
En vérité, vous pouvez remplacer le / par n'importe quel autre caractère (un point par exemple). Voir supprimer une partie de chaîne pour plus de détails.
Manipulation avancée de chaînes de caractères
Extraire une sous-chaîne (bash uniquement)
Simplement avec la syntaxe ${chaine:début:longueur}.
chaine="Trucs et astuces en shell" echo ${chaine:0:16} # Affiche "Trucs et astuces"
Ou avec cut :
cut -cN-M # N : position du début, M : position de la fin
Remplacer une sous-chaîne par une autre (bash uniquement)
On peut remplace la première occurrence uniquement :
chaine_de_base="J'aime les pommes et les framboises" remplacer_pomme_par="fraises" chaine_corrigee=${chaine_de_base/pommes/$remplacer_pomme_par}
On peut aussi remplacer toutes les occurrences avec :
chaine_corrigee=${chaine_de_base//pommes/$remplacer_pomme_par}
On peut aussi remplacer le début ou la fin :
fichier="/root/script.py" echo ${fichier/#\/root/\/tmp} echo ${fichier/%.*/.sh}
Ce qui donne :
/tmp/script.py /root/script.sh
Passer du texte en majuscule/minuscule (bash uniquement)
a=COUCOU echo ${a,,} # affiche "coucou"
a=coucou echo ${a^^} # affiche "COUCOU"
On peut aussi passer juste la première lettre en majuscule/minuscule :
a=coucou echo ${a^} # affiche "Coucou" a=Coucou echo ${a,} # affiche "coucou"
Supprimer une partie de chaîne
Pour supprimer la plus courte partie d'une string en partant du début, il suffit d'utiliser la syntaxe ${chaine#sous-chaine}. Pour partir de la fin : ${chaine%sous-chaine}.
fichier="/var/tmp/" echo ${fichier#*/} # Affiche "var/tmp/" echo ${fichier%/*} # Affiche "/var/tmp"
Pour supprimer la plus longue partie possible d'une chaîne, il suffit de doubler le caractère :
fichier="/var/tmp/toto" echo ${fichier##*/} # Affiche toto fichier=var/tmp/toto echo ${fichier%%/*} # Affiche var
Générer des nombres aléatoires
Tire un nombre aléatoirement entre 0 - 32767 (bash uniquement) :
$RANDOM
Si RANDOM n’est pas disponible, la commande fortune qui tire aléatoirement un proverbe l’est peut être. On en prend la somme pour obtenir un nombre.
fortune | cksum | cut -f1 -d" "
Utilise la date où le PID du dernier processus.
seed=$(( echo $$ ; time ps ; w ; date ) | cksum | cut -f1 -d" ")
Utilise l’entrée d’entropie du noyau. C’est la meilleur méthode, la plus robuste pour générer de l’aléatoire.
dd if=/dev/urandom count=1 2> /dev/null | cksum | cut -f1 -d" "
Savoir si une chaîne est contenue dans une autre
Avec la fonction test (bash uniquement)
[[ reg_exp =~ contenant ]]
Avec grep
grep -q "reg_exp" chaine
Renommer les fichiers en fonction d’une expression régulière
for file in `ls` ; do new_name=`echo $file | sed 's/\(.*\)\.dump\(.*\)\.sql/\2.\1.sql/'` mv $file $new_name done
On peut également utiliser Emacs.
Savoir si un script est lancé dans un shell interactif
La commande tty -s renvoie 0 si le script est lancé dans un terminal interactif et 1 sinon.
Chmod a+X
chmod a+X va donner les droits d'exécution à un fichier uniquement si les droits d'exécution sont présents pour l'utilisateur, le groupe ou tous. Par exemple :
$ mkdir test $ mkdir test/folder $ mkdir -m 600 test/weired_folder $ touch test/script $ chmod +x test/script $ touch test/file
Les droits sont donc :
-rw-r--r--. 1 jenselme jenselme 0 Feb 20 23:02 file drwxr-xr-x. 2 jenselme jenselme 40 Feb 20 23:01 folder -rwxr-xr-x. 1 jenselme jenselme 0 Feb 20 23:02 script drw-------. 2 jenselme jenselme 40 Feb 20 23:02 weired_folder
$ chmod -R a+X
Maintenant les droits sont :
-rw-r--r--. 1 jenselme jenselme 0 Feb 20 23:02 file drwxr-xr-x. 2 jenselme jenselme 40 Feb 20 23:01 folder -rwxr-xr-x. 1 jenselme jenselme 0 Feb 20 23:02 script drwx--x--x. 2 jenselme jenselme 40 Feb 20 23:02 weired_folder
Différences entre les implémentations de certaines commandes entre GNU et BSD
sed
La commande sed de BSD ne connaît pas certains métacaractères tels que \s.
Les opérations dans un fichier se font :
- sed -i'' 's/toto/tata/g' fichier sous GNU mais
- sed -i '' 's/toto/tata/g' fichier sous BSD. La commande
- sed -i -e s/toto/tata/g' fichier est compatible avec les deux versions.