Cette page provenant du wiki
http://ensiwiki.ensimag.fr/index.php/Introduction_aux_scripts_shell traite des scripts shell. Elle a pour objectif de donner, de manière concise, des outils permettant de faire beaucoup de tâches courantes dans un environnement UNIX. Le seul prérequis est le stage UNIX de première année suivi d'une certaine pratique du shell, cette page s'adresse à des utilisateurs UNIX niveau débutant à intermédiaire.
Fichier script
Description
Un script shell est un ensemble de commandes shell rassemblées dans un fichier. L'extension de ce fichier est généralement en '.sh' . Les commandes peuvent se suivre comme si on les tapait successivement dans le terminal, il est également possible de faire des fonctions afin de rendre les scripts plus évolués. Les scripts shell sont souvent utilisés pour automatiser des manipulations sur des fichiers et dossiers : édition, suppression, modifications. On peut par exemple écrire des scripts qui génèrent des pages HTML de manière automatique.
En tête
Par convention (et je vous recommande très vivement de la respecter), on définit le langage shell utilisé sur la première ligne du script. Ainsi, un script en Bourne shell commencera par :
En pratique, on pourra rencontrer des scripts commençant par
- #!/bin/bash
- #!/bin/ksh
- etc.
pour d'autres shell UNIX. Dans la suite, nous utiliserons le Bourne shell.
Commentaires
Le script est un langage de programmation à part entière et certaines lignes d'instructions font parfois beaucoup de choses. Les commentaires sont alors d'autant plus importants pour pouvoir se relire et être relu.
Dans un script Shell les commentaires sur une ligne commencent par le caractère '#'
- # ceci est un commentaire sur une ligne
Execution
Pour pouvoir rendre un script exécutable, c'est à dire pouvoir le lancer en tapant dans un terminal la commande
il faut le rendre exécutable.
Pour cela, il faut modifier les droits de ce fichier de la manière suivante :
Les variables
Création
Le shell donne la possibilité de créer des variables, comme dans tous les langages de programmation. Contrairement aux langages compilés comme l'Ada, le C/C
, Java, etc. ... les variables n'ont pas besoin d'être déclarées avant leur utilisation et ne sont pas typées. En fait les variables en shell sont toutes de type 'chaine de caractère'.
En général dans un script shell, il est d'usage d'écrire les variables en majuscules afin de faciliter la lecture
'''Remarque''' : les variables Shell sont globales et donc restent accessible partout dans un script
Ceci est la variable MESSAGE dans laquelle on a stocké la chaine de caractère ''hello world''.
Notez qu'il n'y a pas d'espaces des deux côtés du signe égal, cela ne fonctionnerait pas s'il y en avait. Le shell est assez pointilleux sur ce point contrairement à la plupart des langages compilés cités plus haut.
Utilisation
Pour récupérer accéder à la valeur d'une variable, il faut faire précéder son nom du caractère $, le tout entoure de guillemets. Par exemple, pour afficher le contenu de la variable MESSAGE en console (en utilisant la commande '''echo''')
'''Remarque''' : Les guillemets ne sont pas toujours obligatoires dans la mesure où si la variable ne contient pas d'espaces, ça marchera sans : par exemple si on est absolument certain que la variable que l'on utilise représente un nombre. Avec les guillemets, cela marchera tout le temps, même si cela alourdit le code.
Par exemple, un cas ou les guillemets sont obligatoires : supposons que l'on parse une page HTML ligne a ligne et que l'on veut détecter des lignes de tableau commençant donc par : ''<TR><TD><A''
Dans la variable DEBUT on met le debut de la ligne de code HTML.
On fait par exemple le test suivant:
- if [ $DEBUT = "<TR><TD><A" ]
- then
- fi
Si celle ci commence par ''<img src="'' ce la ne fonctionnera pas à cause du caractère ''<''.
Par contre le code suivant marchera
if [ "$DEBUT" = "<TR><TD><A" ]
then
#code
fi
La présence de caractères spéciaux pour le Shell dans les variables (comme les espaces) implique l'utilisation des guillemets. De manière générale, il est conseillé de les mettre, même si cela détériore la lisibilité du fichier
Concaténations
Les variables étant toutes du type chaine de caractère, il est possible de les concaténer, ou de les compléter simplement en les écrivant côte à côte. Par exemple :
PARTIE_1="hello"
PARTIE_2="world"
MESSAGE="$PARTIE_1" "$PARTIE_2"
- # ou encore
- MESSAGE="${PARTIE_1}${PARTIE_2}"
- # les accolades servent à délimiter le nom des
- # variables de manière à ce qu'il n'y ait pas d'ambiguités
- # c'est surtout utile dans le cas suivant
- MESSAGE="${PARTIE_1}world"
- # qui produit exactement le même résultat que la commande précédente
Affectation du résultat d'une commande
Les résultats de commande : par exemple ''ls'' sont des chaines de caractères et il est donc possible de les stocker dans une variable.
De manière générale, cela se fait de la manière suivante:
- VARIABLE=$(commande)
- # ou
- VARIABLE=`commande`
Par exemple :
- CONTENU=$(ls)
- # ou
- CONTENU=`ls`
Fonctions
Il est possible de faire des fonctions dans les scripts Shells. Ces dernières présentent les mêmes intérêts que dans le cas de la programmation classique en langages compilés : éviter les répétitions de code.
Les fonctions peuvent prendre des paramètres mais a l'inverse des langages compilés cela se fait de manière invisible sans même que l'on ait a déclarer quoi que ce soit, ce qui peut se révéler déroutant au premier abord.
Voici comment déclarer une fonction :
ma_fonction()
{
# ecrire du code ici
}
Le code peut utiliser les variables $1, $2, ... , $9 qui sont les paramètres passés a la fonction. Quel que soit le nombre de paramètres utilisés, l'en-tête de la fonction reste inchangé.
Pour appeler une fonction on écrit son nom suivi de la suite des paramètres qu'on lui passe, séparés par des espaces
- ma_fonction PARAM_1 PARAM_2 PARAM_3 PARAM_4 PARAM_5 PARAM_6 PARAM_7 PARAM_8 PARAM_9
Par exemple, la fonction suivante
dire_bonjour()
{
echo "Bonjour"
echo "comment allez vous ?"
}
Aura pour effet d'écrire dans la console :
- >Bonjour
- >comment allez vous ?
c'est à dire remplacer l'écriture des deux '''echo'''.
Cette fonction est sans paramètres et est appelée comme ceci
Un exemple de fonction avec 2 paramètres
# paramètres
# <PREMIERE_CHOSE_A_DIRE>................$1
# <DEUXIEME_CHOSE_A_DIRE>................$2
# utilisation :
# dire "$PREMIERE_CHOSE_A_DIRE" "$DEUXIEME_CHOSE_A_DIRE"
# où PREMIERE_CHOSE_A_DIRE et DEUXIEME_CHOSE_A_DIRE sont des variables
# ou des chaines de caractères
dire()
{
echo "Bonjour, j'ai ceci a vous dire :"
echo "premièrement: $1"
echo "et deuxièmement: $2"
echo "merci de votre attention"
}
Comme les paramètres ne sont jamais indiqués dans le prototype de la fonction, il est conseillé de les mettre en commentaire avant la fonction, comme ci dessus et ce, afin de rendre compréhension, relecture et débuggage possibles.
Utilisation :
PREM="hello"
DEUX="world"
dire "$PREM" "$DEUX"
# ou encore pour le même résultat :
dire "$PREM" "world"
Commandes de base
Les pipes
Le pipe est un outil qui permet d'aligner des commandes Shell. Il est donc assez difficile de bien les expliquer sans connaitre de commandes. Cependant, dans la liste de commandes suivantes, il était très intéressant parfois de montrer quelques combinaisons assez pratiques. Donc si vous ne connaissez pas les commandes utilisées dans cette section, il est conseillé de poursuivre en ignorant les partie/lignes contenant le caractère |.
Le pipe donc permet de faire correspondre la sortie d'une commande à l'entrée d'une autre. Une commande Shell peut être constituée d'autant de pipes que l'on veut.
Un pipe, avec deux commandes au total (ce qui est le minimum), s'écrit de la manière suivante
Au fur et a mesure que la commande 1 produit son résultat, celui ci est interprété par la commande 2. Bon c'est un détail mais il fait que l'exécution est rapide.
L'exemple le plus utilisé est de faire un pipe avec '''grep''' en récepteur (piper avec grep dira t-on ...)
Par exemple :
ls | grep "un_bout_de_nom_de_fichier"
'''grep''' ira chercher dans le résultat de '''ls''' une chaine de caractères avec un_bout_de_nom_de_fichier dedans
Les possibilités offertes par les pipes sont grandes :
par exemple :
ls -l | cut -b2
ls -l | sed -e s/"user"/"hello user"/
...
La première commande renvoie la liste du deuxième caractère du résultat de la commande '''ls -l''' et la seconde ligne de commande remplace pour chaque ligne du résultat de la commande '''ls -l''' la chaîne de caractère ''user'' par la chaîne ''hello user''
Par contre, on peut imaginer la commande suivante pour supprimer tous les fichiers dont le nom contient ''truc''
En fait cela ne marchera pas, car rm n'est pas fait pour lire un flux de données.
Pour que cela marche, il faut dire a '''rm''' que le résultat de la commande qui le précède passe dans ses paramètres.
Le mot clé pour cela est '''xargs'''
ainsi
ls | grep "truc" | xargs rm
fonctionnera.
De même, imaginons que l'on veuille chercher une chaine de caractères précise dans tous les fichier d'un répertoire :
en supposant qu'il n'y a que des fichiers dans le répertoire courant, la commande
ls | grep "chaine de caracteres a chercher"
ne fera pas ce que l'on veut : elle va chercher la chaine de caractères dans le résultat de la commande '''ls'''
Ici, c'est '''xargs''' qui résoud le problème :
ls | xargs grep "chaine de caracteres a chercher"
Cela n'est certes pas facile à comprendre du premier coup, (ni à expliquer clairement d'ailleurs). Il faut essayer et tâtonner un petit peu, après cela devient quasiment naturel de savoir si l'on met '''xargs''' ou pas.
En pratique, si la commande cible du pipe (ie celle qui est a droite) est capable de lire un fichier : cut, sed, grep ... , ce n'est pas la peine de mettre '''xargs''' mais il y a des exceptions (cf l'exemple précédent)
Redirections
Il est possible de rediriger les sorties des commandes vers des fichiers :
Un simple chevron
pour mettre la sortie de la commande dans un fichier
Ex:
Doubles chevrons pour ne pas écraser le fichier si il existe déjà et mettre le résultat de la commande a la suite de ce qu'il y a déjà dans le fichier.
Les erreurs éventuellement levées par les commandes ne sont pas considérées comme une sortie standard. Les simple et doubles chevrons ne les affectent donc pas. Pour rediriger la sortie d'erreur, l'opérateur est
Il est possible de combiner > et 2> pour mettre la sortie d'erreur dans un autre fichier que la sortie standard, avec une commande ou un script Shell:
commande > output.txt 2> err.txt
# peut se faire avec des scripts (qui sont aussi des commandes)
script.sh > output.txt 2> err.txt
Avec le shell bash, on peut mettre les deux sorties dans le même fichier avec l'opérateur
(attention, cette syntaxe n'est pas POSIX et ne marchera pas avec tous les shells, typiquement pas avec le /bin/sh de Debian et Ubuntu)
cat
Plusieurs utilisations : affichage, édition et concaténation de fichiers
Sert a afficher le contenu d'un fichier appelé ainsi
assez utile, cat (en version GNU) permet de numéroter les lignes (entre autres, voir ''cat --help'' pour toutes les autres fonctionnalités)
Sert a éditer un fichier
cat > fichier.txt << EOF
Bla
bla
bla
EOF
EOF (pour End Of File) est la balise qui sert a indiquer a cat quand est ce que l'on veut arrêter l'édition.
La chaine EOF n'est pas obligatoire, on peut mettre ce que l'on veut mais il faut choisir une chaine de caractères que l'on ne souhaite pas mettre dans le fichier. Par exemple les mots THE_END, ou C_FINI feront parfaitement l'affaire, c'est juste une convention de terminer avec EOF, rien de plus.
Dans la commande ci dessus, si le fichier existe, son contenu sera effacé (ou pas : en fait cela dépend du Shell que vous utilisez mais parfois il vous indiquera que le fichier existe et qu'il ne peut pas l'écraser)
Pour écrire a la suite d'un fichier et donc conserver ce qu'il y a déjà d'écrit dedans, il faut utiliser deux chevrons au lieu d'un seul
cat >> fichier.txt << EOF
Bla
bla
bla
EOF
De maniere générale pour les redirections de flux dans les fichiers : un chevron > pour effacer le contenu s'il existe, créer le fichier s'il n'existe pas et deux chevrons >> pour écrire a la suite du fichier, et également le créer si il n'existe pas.
''cat'' sert également a con''cat''éner des fichiers et afficher le résultat en console. On pourra donc rediriger le flux dans un fichier si l'on veut enregistrer cela.
cat fichier1.txt fichier2.txt > resultat.txt
Sur cet exemple on concatene deux fichiers mais on peut en concaténer autant que l'on veut
head et tail
head
Permet d'afficher les premières lignes d'un fichier (10 premières par défaut mais on peut lui préciser combien)
# affiche les 10 premieres lignes
head fichier.txt
# affiche les $NOMBRE premieres lignes
head -$NOMBRE fichier.txt
tail
Pareil que head mais en partant de la fin d'un fichier
# affiche les 10 dernieres lignes
tail fichier.txt
# affiche les $NOMBRE dernieres lignes
tail -$NOMBRE fichier.txt
Sélectionner de la ligne L1 a L2
À titre d'illustration, voici comment extraire la portion du fichier contenu entre la ligne L1 et la ligne L2
(Une version plus efficace serait
sed -n $L1,$L2p fichier.txt
).
Cas particulier: sélectionner la ligne N
Utilisation combinée de head et tail au moyen d'un pipe
- N=42
- head -$N fichier.txt | tail -1
Cas général
Il faut juste calculer le nombre de lignes a extraire : L2-L1+1 ou L2-L1 selon si l'on veut sélectionner les extrêmes ou pas
NB_LIGNES=$((L2 - L1 + 1))
head -$L2 fichier.txt | tail -$NB_LIGNES
grep
Description
Permet de chercher une chaîne de caractères parmi un flot de données (fichier texte, ou directement résultat de commande affiché en console en utilisant des pipes)
Utilisation de base :
- grep "chaine de caractere a chercher" fichier_ou_chercher.extension
grep fonctionne ligne à ligne : il affichera par défaut, toutes les lignes contenant la chaîne de caractères à chercher.
On peut aussi faire avec un pipe :
- cat fichier.txt | grep "chaine a chercher"
Certains diront que c'est un [http://partmaps.org/era/unix/award.html usage inutile de ''cat'']. Cependant avec cette commande la chaîne à chercher est mise an relief dans le terminal.
Quelques options utiles
L'option -n permet de numéroter les lignes ce qui peut s'avérer pratique par exemple si on veut supprimer la ligne du fichier.
- grep -n "chaine de caractere a chercher" fichier_ou_chercher.extension
C'est équivalent a un
- cat -n fichier.extension | grep "chaine a chercher"
L'option -v permet de sélectionner toutes les lignes sauf celle qui contiennent la chaine de caractères spécifiée
Exemple :
- grep -v "indesirable" fichier.extension
Toutes les lignes contenant le mot indésirable dans le fichier fichier.extension ne seront pas affichées
L'option -A (attention, pratique mais pas portable) permet d'afficher un nombre de lignes directement apres la ligne ou se trouve la chaine a chercher. Ce nombre de lignes est a spécifier juste apres. (A pour after)
Exemple
grep -A5 "trouver" fichier.extension
affichera les 5 lignes suivant chaque ligne ou se trouve le mot '''trouver'''
L'option -B (pour before), exactement comme -A mais pour les lignes avant cette fois.
L'option -a combine les deux précédentes options. en affichant un certain nombre de lignes avant et après celle contenant la chaine de caracteres cherchée.
grep est aussi compatible avec les expressions régulières : pour chercher toutes les lignes contenant un chiffre, une solution est
grep [0-9] fichier.extension
find
La commande '''find''' est en quelque sorte un '''ls''' récursif qui cherche des fichiers ou dossiers
- dans toute une arborescence a partir d'un répertoire racine spécifié (./ par défaut)
Par exemple :
find /home/paul/projet_c/ -name "*.c"
affichera tous les fichiers dont l'extension est en .c dans le répertoire projet_c de paul.
Plus précisément, la commande affichera les fichier avec tout leurs chemins d'accès en incluant celui spécifié, en l'occurrence : /home/paul/projet_c/
Par exemple la recherche pourrait donner le résultat suivant
- /home/paul/projet_c/src/main.c
- /home/paul/projet_c/src/game_engine.c
- /home/paul/projet_c/src/display_engine.c
on peut chercher plusieurs choses grâce a l'option -o (pour ''or'') :
find /home/paul/projet_c/ -name "*.c" -o -name "*.h"
cherchera aussi les fichiers .h
On aura donc par exemple le résultat suivant :
/home/paul/projet_c/src/main.c
- /home/paul/projet_c/src/game_engine.c
- /home/paul/projet_c/src/display_engine.c
- /home/paul/projet_c/inc/display_engine.h
- /home/paul/projet_c/inc/game_engine.h
wc
Compteur de caracteres.
Affichera dans l'ordre : le nombre de lignes, mots et caractères dans fichier.txt.
L'option -l est très utile pour compter les lignes d'un fichier
ou pour avoir directement le résultat (sinon le nom du fichier est rappelle a cote) :
-m pour avoir le nombre de caractères et -w (word) pour le nombre de mots
cut
En considérant qu'une sortie console, un fichier sont des tableaux de caractères, '''cut''' permet de faire des découpes suivant l'axe vertical. cut permet donc de découper (au sens de sélectionner certaines parties) des chaines de caractères.
On va prendre pour exemple la chaine de caractères
- PHRASE="bonjour chers lecteurs de l'ensiwiki, comment allez vous"
Il est possible de définir quels délimiteurs utiliser pour cette chaine de caractères. Comme c'est une phrase avec des mots, avec l'option '''-d''' suivie du délimiteur voulu. On peut par exemple choisir l'espace " " pour sélectionner les mots que l'on veut dans cette phrase.
Pour sélectionner le 3 ième mot de la phrase, la commande sera donc
echo "$PHRASE" | cut -d" " -f3
Si on veut sélectionner les 3 premiers mots
echo "$PHRASE" | cut -d" " -f-3
Si on veut sélectionner a partir du troisième mot
echo "$PHRASE" | cut -d" " -f3-
Si on veut sélectionner du troisième au sixième mot compris :
echo "$PHRASE" | cut -d" " -f3-6
'''Question :'''
Si on veut sélectionner le dernier mot sans connaitre combien il y a de mots ?
(''indice : aller voir rev'')
Application tres pratique : sélectionner uniquement le nom de fichier en sortie de '''find''' qui lui affiche tout le path a partir du répertoire qu'on lui a précisé.
Ici sur l'exemple il n'y a qu'une seule ligne mais cut marche sur plusieurs lignes et fera des découpes (on peut aussi appeler ca des sélections aussi ...) verticales.
On peut aussi directement spécifier a '''cut''' les numéros de caractères que l'on veut découper. Cela se fait avec l'option '''-b''' Les caractères se numérotent naturellement de gauche a droite, en commençant a 1.
Sélection du 42 ieme caractère dans la phrase ci dessus
- echo "$PHRASE" | cut -b42
jusqu'au 42
- echo "$PHRASE" | cut -b-42
depuis le 42
- echo "$PHRASE" | cut -b42-
du 24 au 42
- echo "$PHRASE" | cut -b24-42
rev
Permet de renverser une chaine de caracteres
retourne
Exemple :
sed
sed (Stream EDtior) est un éditeur de fichiers et procède ligne par ligne. C'est une commande très puissante, dont l'utilisation la plus courante est de remplacer des chaînes de caractères dans des fichiers (ou à l'intérieur d'un pipe).
Utilisation basique
Pour remplacer toutes les chaînes de caractères par une autre
sed -e "s/"chaine a remplacer"/"nouvelle chaine/g" fichier
Pour remplacer la première occurrence sur chaque ligne de la chaîne de caractère spécifiée, on ne met pas le '''g'''
sed -e "s/"chaine a remplacer"/"nouvelle chaine/" fichier
Certains caractères sont a échapper comme le point . ou les guillemets "
et également le slash car il est utilisé comme délimiteur dans la commande. Si la chaîne à remplacer comporte beaucoup de slash, on peut utiliser d'autres caractères pour délimiter : le # peut être un bon choix
Le début de ligne est codé par ^
La fin de ligne par $
Le retour à la ligne pour spécifier par quoi on veut remplacer: \n (comme en C)
Tabulation : \t
Par défaut, le résultat s'affiche en console. Pour modifier le fichier traité, il faut utiliser l'option -i
sed -i -e "s/"chaine a remplacer"/"nouvelle chaine/g" fichier
Enregistrements
sed permet également de faire du pattern matching ligne à ligne et supporte les expressions régulières :
Supposons que l'on veuille détecter toute les lignes d'un fichier qui à n'importe quel endroit contiennent la chaîne de caractère "" (soit 5 underscore accolés) suivi d'un nombre de caractères quelconques et de la chaîne "ttttt" puis un nombre de caractères quelconques jusqu'à la fin de ligne.
Par exemple la ligne suivante devrait être détectée :
- Apollo 11 est la première mission spatiale à avoir conduit un ttttt homme sur la Lune.
Supposons que l'on ne veuille conserver que ce qu'il y a entre et ttttt :
la commande sed suivante fait cela :
- sed -e "s/\( .*\)\( .*\)ttttt\( .*\)/\2/"
Les expressions
correspondent aux enregistrements : les \ sont là pour échapper les parenthèses qui ont un sens pour '''sed''' autrement.
le point est là pour désigner n'importe quel caractère et l'astérisque sa répétition quelconque à partir de 0. Ici donc '''sed''' va enregistrer n'importe quelle chaîne de caractères et s'arrêtera quand il repèrera les 5 underscore.
Le \2 représente le second enregistrement c'est à dire ce qui se trouve entre et ttttt.
Il est possible de faire jusqu'à 9 enregistrements dans un '''sed''' qui seront restitués par \1 ... \9
Informations supplémentaires
Plus d'infos sur '''sed''' ici
http://anaturb.net/sed.htm
bc
bc (binary calculator) est un outil permettant de faire des calculs, entier et a virgule flottante principalement.
On peut l'utiliser de la maniere suivante (mais bien sur ce n'est pas la seule facon de l'utiliser)
echo "scale=<nombre de chiffres apres la virgule voulus>;<calcul a effectuer>" | bc
Par exemple, si on veut faire le rapport entre deux variables, avec une precision au centieme :
echo "scale=2;$VAR_1/$VAR_2"| bc
L'argument '''scale''' n'est pas obligatoire. Sa valeur est par défault 0 si on ne précise rien, ce qui permet de faire des calculs avec des résultats entiers
'''bc''' permet egalement de faire des comparaisons sur des nombres et renvoie soit 0 pour vrai soit 1 pour false (comme en C)
Par exemple
renverra 1
On a donc ici un outil pour faire des tests sur des entiers flottants ... (le shell ne les supportant pas les comparaisons de flottants sans utiliser '''bc''').
if [ $(echo "$VAR1 < $VAR2" | bc) -eq 1 ]; then
fi
sort
sort est une commande qui permet de trier des chaines de caractères par ordre alphabétique. Donc caractère par caractère, en partant de la gauche.
Pour trier des nombres, attention : 42 est plus grand que 7 mais par défaut, sort compare d'abord 7 et 4 et placera 7 avant 42 donc. L'option <code>-n</code> de sort permet de gérer ce cas, en faisant un tri numérique et non alphabétique.
uniq
La commande '''uniq''' permet d'éliminer les doublons dans une liste triée
convert
''convert'' n'est pas une commande Shell de base. En fait c'est une commande de [http://www.imagemagick.org/ ImageMagick?], logiciel pour la manipulation d'images. Elle est très pratique car elle permet de convertir rapidement des fichiers dans tous les formats d'images (PNG,JPG,GIF ...) mais aussi de convertir un fichier PDF (donc vectoriel en image).
Sur Ubuntu elle est installée de base mais ce n'est peut être pas le cas dans d'autres distributions.
Conversion redimensionnement d'images
Quelques exemples :
convert image.gif image.jpg
convert image.gif image.png
convert image.png image.jpg
- ...
On peut aussi redimensionner via l'option resize
convert image.gif -resize 100x200 image.jpg
Conversion de PDF en image
Pour la conversion d'un PDF en image, vu que le format PDF est vectoriel, on peut choisir la qualité de l'image en sortie :
Par exemple
convert -density 400 fichier.pdf -resize 25% fichier_.gif
l'option '''density''' fait référence aux dpi.
Pour faire varier la résolution de l'image en sortie il faut jouer sur les options '''density''' et '''resize'''
Couper une image
L'option -crop permet de couper une image, d'en sélectionner une partie
convert image.gif -crop 100x200+10+20 image_out.gif
Crée l'image image_out.gif de taille 100 pixels de large et 200 pixels de haut, qui est une partie de image.gif, dont le coin supérieur gauche correspond au point de coordonnées (10,20) dans image.gif.
En général, dans la programmation graphique, l'origine du repère est prise dans le coin supérieur gauche des images, et c'est le cas ici. Les axes des abscisses et des ordonnées restent toujours respectivement horizontaux et verticaux, le premier pointe vers la droite et le second vers le bas.
Générer des graphiques dans des scripts
Cela est possible (entre autres) avec le logiciel de statistiques R. (pour les premières années un coup d'apt-get/aptitude install ...)
Un moyen de le faire est de rentrer la commande qui générera le graphique dans un fichier texte a coups de cat (comme vu plus haut)
cat > R_command.txt << EOF
x=c(1,2,3,4,5,6)
y=c(2,5,9,8,3,7)
plot(x,y)
EOF
Puis on affiche le tout avec cat et on pipe avec R avec l'option save
cat R_command.txt | R --save
Penser a nettoyer les fichiers temporaires apres.
Cela produit un fichier PDF : Rplots.pdf contenant le graphique en question.
Il est possible de le convertir a sa guise ensuite grâce à '''convert''' vue plus haut
Envoyer un mail
On peut utiliser pour cela la commande '''mailx'''
Exemple :
-
cat > corps.txt << eof
bla bla
bla
eof
cat corps.txt | mailx -s "sujet de mail ici" addressemail@trucmuche.fr
Instructions de contrôle
Le Shell permet d'effectuer les instructions de contrôle basiques et classiques en programmation : ''if'', ''while'' et ''for''
Attention à bien respecter la forme décrite dans les exemples ci dessous car le Shell est très sensible aux fautes de syntaxe/typographie. Un espace en trop ou en moins peut faire que le Shell ne comprendra pas ce que vous voulez faire.
L'instruction if
L'instruction ''if'' s'écrit de la manière suivante :
if [ condition ]; then
# code ici
fi
ou encore
if [ condition ]
then
# code ici
fi
La présence du point virgule est équivalente à un retour chariot.
Notez bien la présence d'un espace après le crochet ouvrant et avant le crochet fermant ...
On peut donner ici les exemples les plus courants de '''condition'''.
On désigne par
deux variables Shell (donc des chaines de caractère par défaut).
La première condition la plus utilisée est de comparer $VAR_1 et $VAR_2 en tant que chaines de caractères
if [ $VAR_1 = $VAR_2 ]
then
# code ici
fi
La aussi notez la présence des espaces de part et d'autre du signe "="
On peut bien sûr comparer une variable avec une chaine de caractère ou encore deux chaines de caractères différentes et fixées (ce qui présente quand même peu d'intérêt)
if [ $VAR_1 = "valeur fixee" ]
then
# code ici
fi
- # ou encore
if [ a = b ]
then
# mouais ...
# vu que a n'est pas égal à b on ne passera
# jamais ici
fi
Conditions : tests possibles
On peut effectuer des test sur les variables (ou des chaines de caractères, cela revient au même) :
-e pour tester l'existence (exists)
-d pour un dossier (directory)
-f pour un fichier (file)
-
VAR_1=/home/user/file
if [ -e $VAR_1 ]
then
# code ici
fi
VAR_1=/home/user/dossier
if [ -d $VAR_1 ] # si VAR_1 est un dossier ...
then
# code ici
fi
VAR_1=/home/user/file.txt
if [ -f $VAR_1 ] # si VAR_1 est un fichier ...
then
# code ici
fi
Le Shell permet de faire des tests en interprétant des variables comme des nombres.
-eq égal
-ne différent (not equal)
-le inférieur ou égal (lower equal)
-ge supérieur ou égal (greater equal)
-lt inférieur à (lower than)
-gt supérieur à (greater than)
Exemple
VAR_1=24
VAR_2=42
if [ $VAR_1 -le $VAR_2 ]
# $VAR_1 et $VAR_2 doivent faire référence à des nombres
then
# code ici
fi
ou encore
VAR_1=24
if [ $VAR_1 -le 42 ]
# $VAR_1 doit faire référence à un nombre
then
# code ici
fi
Tester si une variable est vide
Dans un script, on peut vouloir faire un test sur le résultat d'une commande : en particulier savoir si elle a renvoyé quelque chose ou pas. Par exemple un grep. L'idée est de mettre le résultat de la commande dans une variable et concaténer cette variable avec n'importe quoi : typiquement :
VAR=$(ls)
if [ "${VAR}"1 = 1 ]
then
rm -rf *
fi
'''Remarque''' : ici les guillemets dans le test du ''if'' sont obligatoires sinon cela plantera a partir du moment ou l'on aura plus de deux éléments dans le répertoire courant : en effet, cela implique que la variable ''VAR'' contiendra des espaces donc si l'on ne mets pas de guillemets, le Shell interprètera chaque mots séparément au lieu d'un seul bloc contenant des espaces.
Attention, la condition d'égalité est assez sensible aux espaces, tabulations, retour ligne. Il est préférable de ne prendre que la premiere ligne de résultat de la commande (grace á la commande ''head -1'') et de supprimer espaces et tabulations (sed)
Ainsi pour reprendre l'exemple exemple :
VAR=$(ls | head -1 | sed -e s/" "/""/g -e s/"\t"/""/g)
Aura plus de chance de fonctionner
Negation
La négation se fait comme en C/C, Java : avec un point d'exclamation
Exemple
if [ ! "$VAR_1" = "$VAR_2" ]
then
# code ici
fi
and et or pour les conditions
-a pour and
-o pour or
if [ ! "$VAR_1" = "$VAR_2" -a "$VAR_3 = $VAR_4" ]
then
# code ici
fi
L'instruction for
L'instruction ''for'' permet de faire une boucle sur un ensemble. Un ensemble est comme toujours en Shell, une chaine de caractères.
Les éléments de l'ensemble sont les "mots" constituant la chaîne de caractère, c'est à dire les suites de caractères contiguës entre deux espaces ou tabulations.
Par exemple :
est un ensemble qui comporte quatre éléments
Syntaxe et exemple de boucle ''for''
ENSEMBLE="valeur1 valeur2 valeur3"
for ELEMENT in $ENSEMBLE
do
# instructions a coder ici
done
- # equivalent à
-
for ELEMENT in $ENSEMBLE; do
# instructions a coder ici
done
- # equivalent à
-
for ELEMENT in $ENSEMBLE; do {instructions a coder ici}; done
'''Remarque:''' Si on met des guillemets autour de <code>$ENSEMBLE</code>, la boucle for iterera sur un seul élément (ELEMENT=valeur1 valeur2 valeur3). Si on ne met pas de guillemet, le shell va découper le contenu de la variable selon les blancs, et va itérer sur les trois valeurs (valeur1, valeur2 et valeur3).
Comment créer des ensembles ? Une solution est d'utiliser la sortie de n'importe quelle commande produisant une suite d'éléments séparés par des blancs.
'''Attention:''' On serait tenté d'utiliser la commande '''ls''' pour produire un ensemble. C'est une très mauvaise idée :
for ELEMENT in `ls`
do
# instructions
done
ou encore
for ELEMENT in $(ls)
do
# instructions
done
Dans les deux cas, on va exécuter la commande ls, et redécouper la sortie de ls après coup. Si un fichier contient un espace ou autre caractère spécial du shell, la boucle ne marchera pas. Par contre, la boucle suivante :
for ELEMENT in *
do
# instructions
done
fait ce qu'elle doit faire dans tous les cas : l'expansion du jocker « * » étant faite après l'interprétation des blancs, les caractères spéciaux ne posent aucun problème ici. Par ailleurs, cette syntaxe évite de lancer une commande externe ls, et est donc plus efficace.
Une autre utilisation intéressante de la boucle for est d'itérer sur les arguments d'une fonction ou d'un script :
for ELEMENT in "$@"
do
# instructions
done
La commande seq
Faire une boucle sur des entiers de n1 à n2 :
Cela peut se faire au moyen d'une boucle ''while'' mais on peut le faire également grâce à la commande '''seq'''
for X in $(seq $N1 $N2)
do
#code
done
L'instruction while
La syntaxe d'une boucle while est la suivante:
while [ condition ]
do
# instructions
done
où '''condition''' est exactement du même type que ceux des structures ''if''
Pour faire une boucle for allant d'un entier n1 a un entier n2 on peut faire ainsi
N1=24
N2=42
i=$N2
while [ $i -le $N2 ]
do
# instructions
# i++
i=$(echo $i+1 | bc)
done
Exemple(s)
Vous avez une arborescence dans laquelle se trouve des fichiers jpg (imaginons que ce sont des fichiers scannés et que votre scanner ne les convertisse pas directement sous format pdf). Vous voulez sélectionner tous ces fichiers et les convertir en pdf sans a avoir a taper 1000 fois
- convert fichier.jpg fichier.pdf
Le script suivant convertit en pdf tous les fichiers jpg contenus dans l'arborescence courante et les rappatrie dans le repertoire courant
-
#!/bin/sh
find . -name "*.jpg" > temp.txt
for l in $(seq 1 $(cat temp.txt | wc -l)); do # pour toutes les lignes de temp.txt (chaque ligne = un nom de fichier)
f=$(sed -n $l,${l}p temp.txt) # sélectionner la ligne l
echo "$f"
nom="$(echo "$f" | cut -d"." -f2 | sed "s/ /_/g" | rev | cut -d"/" -f1 | rev).pdf" # renommer en extension pdf
echo "${nom}"
convert "$f" "$nom"
echo
done
rm temp.txt
Trouver tous les fichiers java dans l'arborescence courante qui contiennent la chaine de caractères passée en paramètre :
#!/bin/sh
for file in $(find . -name "*.java")
do
res=$(cat $file | grep "$1")
if [ ! "${res}1" = 1 ]
then
echo $file
fi
done
Les outils UNIX sur windows ?
Il est possible d'émuler un shell UNIX avec les outils associés (terminal, commandes de base, ...) sur Windows ce qui peut s'avérer pratique pour profiter des nombreuses fonctionnalités vues ici.
Deux programmes permettent cela : Cygwin? et MinGW?.