Domaine public 🅭

CMS minimal
ecrit avec VI

[ /  ^ < ]

presentation

exemples
notes       04/12/2024
robuste       06/02/2023
finir proprement       06/02/2023
etrange       06/02/2023
references       06/11/2024

	
	
	
	
	
	


Le Shell

C'est un interpréteur de commandes, qu'on nomme ainsi car il apparait comme une coquille qui entoure le système. On l'utilise principalement dans deux cas : + interface de lignes de commandes proposée à la connexion des utilisateurs, + langage de programmation pour créer d'autres programmes qu'on appelle des scripts. En théorie, c'est la mĂȘme chose car on peut considérer qu'un Shell de connexion est un programme dont le fichier de commande est la console de l'utilisateur. Cela explique pourquoi on peut se déconnecter par Control-D qui est en fait le caractère de fin de fichier. Il est vitale de savoir que les minuscules et les majuscules ne sont pas confondues en shell. Par convention, les noms des commandes sont en minuscules et ceux des variables en majuscules. Dans le texte suivant, l'icone indique une fonctionaitĂ© utile dans un script. 0 - Caractères spéciaux 1 - Variables 2 - Syntaxe des commandes 3 - Commandes sur les fichiers et les repertoires 4 - Commandes sur les fichiers 5 - Commandes sur les repertoires 6 - Commandes sur les fichiers textes 7 - D'autres commandes 8 - Les redirections 9 - Les tests 10 - Les boucles 0 - Caractères spéciaux # commentaire, la suite de la ligne est ignorée ; séparateur d'instruction sur une mĂȘme ligne & exécute la commande suivie de & en tĂąche de fond ( si on veut se déconnecter précéder la commande de nohup ) $! contient le n° de process. pour faire la même chose apres coup ^Z jobs bg [N] # N le numero de job a mettre en tache de fond si plusieurs ` accent grave (en effet peu visible) entoure une commande à exécuter d'abord pour donner le résultat à une autre commande ex: echo "il est `date +%Hh%M`" avantageusement remplacé par $(...) ? remplace un caractère * remplace plusieurs caractères ex : ls a* liste les fichiers commençant par a ex : ls ?a* liste les fichiers dont la deuxième lettre est a \ "protège" un caractère spécial ex : echo * affiche tous les nom de fichier du répertoire courant echo \* affiche le caractère * ^C control C arrête une commande en cours ^J control J indique une fin de ligne ^D control D indique une fin de fichier ( permet de dĂ©connecter ) Particularité en bash la commande history affiche l'historique mais sinon Ă  tout moment: flĂšche vers le haut rappel l'historique des commandes ^R recherche dans l'ihistorique !! affiche est relance la derniĂšre commande mais pour voir: echo !! pour qu'une commande ne soit pas loggĂ©e dans l'historique il suffit de commence la ligne par un espace 1 - Variables Les variables jouent un grand rĂŽle. Certaines peuvent ĂȘtre transmis aux sous-programmes et forment ce qu'on appelle l’environnement. Par contre, une variable définie dans un sous programme disparaĂźt la fin. export NOM=toto ( met la variable dans l'environnement ) env ( affiche l'environnement ) ex : LOGNAME contient le nom de l'utilisateur ex : HOME contient le nom du répertoire de connexion ex : PATH contient les repertoire ou trouver les commandes exécutables ex : PS1 contient le prompt ( qui est affiché à l'invite de saisie ) ex : PS1 contient le nom du repertoire courrant ex : OLDPWD contient le nom du repertoire precedent ex : LINENO contient le n° de ligne dans un script L'usage des variables est un peu délicat : VARIABLE="j'ai envie d'espaces " echo $VARIABLE # les espaces sont concatenées echo "${VARIABLE}ou non" echo '$VARIABLE' # affiche $VARIABLE Les variables 0 à 9 sont dites positionnelles : $0 donne le nom du script, $1 le premier argument .... $# le nombre d'arguments $* tous les arguments mais decoupe ceux contenant des espaces ( typiquement nom de fichier) "$@" résout le problème test "$1" || exec echo "$0 : erreur : parametre manquant" test -f "$1" || exec echo "$0 : erreur : $1 n'et pas un fichier" test -s "$1" || exec echo "$0 : erreur : le fichier $1 est inexistant ou vide" set [...] (assigne les variable positionnelles ) shift (décale les variable positionnelles : 1 est perdu (2 remplace 1, 3 remplace 2 ... ) echo "$0 : nous somme le $(date)" # remplace par le résultat de la commande echo 2+2=$((2+2)) # effectue le calcul jusqu'à 2⁶⁎ echo $n!=$(($(seq -s \* $n))) # la fameuse fonction factorielle grace Ă  la commande seq[uence] ( jusqu'Ă  20! ) seq -s \* $n | bc (echo 1; seq $n | sed 's/$/*/'; echo p) | dc La variable $$ contient le numero du process : nom_fichier$$ ( unique mais seulement sur la machine locale à un instant donné ) mktemp --dry-run nom_fichier_XXXXX # résoud le problème FTEMP=$(mktemp) # crée un fichier dans /tmp DIRTEMP=$(mktemp -d) # crée un repertoire Il existe des tableaux : VAR=(premier second troisieme); I=1; echo ${VAR[$I]} astuce pour exploser une chaine dans un tableau de lettres TAB=($(sed 's/./& /g' <<< abcd)) pour saisir une variable : read -p "j'attends une valeur " NOM_VARIABLE # lancer un programme en boucle par exemple parcequ'il plante until read -t 3 -p "appuie sur [Entree] pour arreter" REP; do programme_qui_plante; done 2 - Syntaxe des commandes Une commande est un ordre que vous donnez au programme shell qui le transmet au système, elle se compose de trois parties : Le nom de la commande les options : un signe - et une lettre par option -h plus moderne : deux signes -- et le nom de l'option --help les arguments auxquels s'applique la commande dans la documentation , [ entoure ce qui n'est pas obligatoire ] exemple : ls [ -l repertoire ] Un manuel en ligne est fourni, pour avoir une explication exemple: man ls Quelques commandes d'usage général : sudo commande ( execute la commande avec tous les droits moyenant une autorisation) ( fichier /etc/sudoers defini qui peut quelles commandes avec ou sans mot de passe ) ( le programme lancé doit appartenir Ă  root dans un repertoire protétégé ) ( sudo -A permet de choisir le programme de demande de mot de passe ( par defaut "askpass" ou variable SUDO_ASKPASS )) !! affiche et réexécute la dernière commande (ex: sudo !! ) exit [n] ( termine le programme , code retour n ( dans variable $? )) # un bout de code utile si on utilise exit #!/bin/bash function finish { # Your cleanup code here } trap finish EXIT exec programme ( remplace le programme en cours par l'autre ) . programme ( lance les commandes dans le mĂȘme shell ) ( indispensable pour définir des variables ) eval chaine ( évalue la chaĂźne etexecute ) ex: C=COMMANDE; COMMANDE=date; eval \$$C type commande ( cherche ou se trouve la commande exécute quand on tape son nom ) : ( deux points ) commande qui ne fait rien utile dans les tests et les boucles infinies certains s'en servent dangereusement pour commenter plusieurs lignes 3 - Commandes sur les fichiers et les répertoires ls [-lrtSh] [rep|fich] ( liste des fichiers du répertoire ) ( -l "long" <=> commande ll ) du [-sh] [fich|rep] ( donne la taille en Ko ) ( -s donne la taille globale ) ( -h format "humain" voir commande di) stat fich|rep ( donne tous les renseignements possible ) ln -s fich|rep ( crée un lien symbolique ) readlink [-f] fich|rep ( si c'est un lien symbolique, donne la cible ) ( -f si plusieurs liens successifs, donne la cible ultime ) 4 - Commandes sur les fichiers chmod a+r fic ( droit de lecture du contenu pour tous ) chmod a+w fic ( droit de modification du contenu pour tous ) chmod a+x fic ( droit d'executer le fichier comme une commande ) rm [-i] [-f] fichier ( remove : effacer ) ( -i interactif, pose une question avant ) ( -f force sauf repertoire et n'envoie pas d'erreur si fichier absent ) cp fich1 fich2 ( recopie le contenu de fich1 en fich2 ) cp -p fich1{,.old} ( recopie fich1 en fich1.old en gardant sa date d'origine ) cp -r rep1 rep2 ( recopie recursivement rep1 en rep2) cp -a rep1{,.ref} ( archive ~ cp -pr rep1 rep1.ref ) cp fich1 repertoire ( recopie fich1 en répertoire/fich1 ) mv fich1 fich2 ( move : renomme ) mv fich1 rep ( move : déplace ) file fichier ( donne les types des fichiers ) find repertoire [-name fichier] [-mtime -1] [-print] [-exec commande \;] find . -type f -iname '*.old' -mtime +10 -exec rm -i {} \; ( effacer les fichiers en .old ou .OLD de plus de 10 jours ) ln fichier1 fichier2 ( link : créer un nouveau lien directe ) ( uniquement à l’intérieur du mĂȘme file system ) cmp fich1 fich2 ( compare le contenu des 2 fichiers ) md5sum fich1 ( calcul le checksum du fichier ) touch [mmjjhhmm] fic ( change la date du fichier ) touch -r fic.ref fic ( copie la date de modification ) cat fich1 fich2 > fich3 ( concatenate ) strings [fichier] ( extrait les caractères imprimables d'un fichier , ex : core (package binutils)) basename /chemin/fichier.truc [.truc] ( affiche seulement le nom de fichier [ sans .truc ] ) dirname /chemin/fichier ( affiche seulement le chemin du ) 5 - Commandes sur les répertoires chmod a+r rep ( donne le droit de lister le contenu pour tous ) chmod a+w rep ( droit d'ajouter, supprimer ou renommer les fichiers) chmod a-w rep ( interdit d'ajouter, supprimer ou renommer les fichiers) chmod g-rwx rep ( interdit tout aux membres du groupe ) pwd ( print working directory: où suis-je # echo $PWD) cd [repertoire] ( change directory ) cd - ( cd dans le répertoire précédent ) cd ~utilisateur ( cd dans le répertoire de l'utilisateur ) ls -d rep ( liste le nom du répertoire et non pas son contenu ) mkdir repertoire ( crée un répertoire ) rmdir repertoire ( efface un répertoire vide ) rm -fr repertoire ( efface un répertoire non vide ) 6 - Commandes sur les fichiers textes cat [fichier] ( vérifier d'abord la lisibilité avec file ) tac [fichier] ( idem, mais en remontant depuis la dernière ligne ) rev [fichier] ( inverse l'ordre des caractère sur chaque ligne ) more [fichier] ( idem en s’arrĂȘtant à chaque page ) less [fichier] ( idem mais permet de remonter dans le fichier ) grep [-i] toto [fich] ( affiche les lignes contenant toto ) ( -i ignore la nuance majuscules / minuscules ) ( -v exclue les lignes contenant toto ) ( grep toto fichier || echo "toto non trouvĂ©" ) ( il existe une version rapide et recursive ripgrep ) lp [-dpr0] [-c] [fichier] ( envoie à l'imprimante [pr0]) ( -c demande à lp de copier le fichier ) pr [-tl 66] [fichier]( prépare le fichier pour ĂȘtre imprimé ( ici remplace les "line feed" par des lignes blanches ) ( -t enlevé les entĂȘtes ) pr -n [fichier] ( numérote les lignes ) nl [fichier] ( idem mais sans en tĂȘtes ) head [-n] [fichier] ( affiche les n premières lignes ) tail [-n] [fichier] ( affiche les n dernières lignes ) tail -f fichier ( ne rend pas la main; affiche ce qui arrive dans le fichier) split [-n] fichier ( découpe en morceaux de n lignes (1000 par defaut)) paste fich1 fich2 ( affiche côte à cĂŽte les 2 fichiers ) fold [-w n] fich1 fich2 ( découpe en lignes de 80 ou n caractères ) cut -cn-m,p fich ( extrait les colonnes de n à m et p mais ne sait pas interverir l'ordre) cut -d: -fn,m- ( le délimiteur est : champs à partir de n ) cut -d'|' -fn,m- ( il faut protéger le pipe ) sort [-unrh] [fichier] ( tri alphabétiquement le fichier ) ( -u ne garde qu'une ligne quand plusieurs identiques ) ( -n tri numérique, sinon 10 < 2 ) ( -r en sens inverse ) ( -h tri numérique humain, 2K < 1G ) diff fich1 fich2 ( affiches les lignes différentes ) sdiff fich1 fich2 ( idem mais en plus affiche les fichiers cote à cote ) vimdiff fich1 fich2 ( idem mais encore plus pratique ) patch [-i fich_diff] fich ( applique les résultat de diff ) tee fich ( recopie l'entrée standard dans fich ) ( conserve une trace d'un affichage : ls | tee trace ) ( pour ajouter à un fichier existant : tee -a fichier ) commande |& fichier # pour aussi recuperer les erreurs uniq [-d] [fichier] ( n'affiche que les lignes répétées) uniq [-u] [fichier] ( n'affiche que les lignes non répétées) xargs commande < fichier ( passe à la commande les paramètre contenu dans fichier) ( indispensable quand on a trop de paramètres ) iconv --from-code LATIN1 --to-code UTF-8 -c inputfile > outputfile 7 - D'autres commandes mail [utilisateur[@MACHINE]] envoie du courrier à l'utilisateur éventuellement sur une autre machine en réseau pour terminer le message : [CTRL] D " mail " seul dépouille son propre courrier write [utilisateur] écrit à l'instant mĂȘme sur l'écran de l'utilisateur pour terminer le message : [CTRL] D mesg [y|n] ( protege l'écran : pas de write ) echo "chaines a afficher" # " conseillées echo -n "total = " # sans retour à la ligne, penser aux espaces en fin de ligne expr 2 + 2 ( affiche 4 ( bien mettre des espaces ) ) expr 10 % 3 ( affiche 1 ( reste de la division ) ) expr aaaa:bbbb:cccc : '\(.*\):' ( affiche aaaa:bbbb ( avant les derniers : ) ) expr aaaa:bbbb:cccc : '\(.*\):.*:' ( affiche aaaa ( avant l'avant derniers : ) ) expr aaaa:bbbb:cccc : '.*:\(.*\)' ( affiche cccc ( après les derniers : ) ) expr aaaa:bbbb:cccc : '.*:\(.*\):' ( affiche bbbb ( après l'avant derniers : ) ) expr aaaa.bbbb.cccc : '\(.*\)\.' ( affiche aaaa.bbbb ( il faut proteger le . ) ) expr 12345 : '.*\(...\)$' ( affiche 345 ( les trois derniers caractères) ) expr abcde : '.*' ( affiche 5 ( le nombre de caractères) ) http://www.regular-expressions.info users donne la liste compacte des utilisateurs connectés who [ am I | -u ] qui est connecté who am I qui suis-je who -u cette option donne plus d'informations ps [-f] [-u utilisateur] [-t terminal] process status : quels sont les programme qui tournent top idem en tableau classé fg [n] remet le le process numéro n ( ou le dernier ) en avant plan script [-a] [fichier] recopie tout ce qui apparaît à l'écran dans un fichier -a ajoute à la fin du fichier kill [-n] PID kill : envoyer un message (n=1..15) à un programme en cours le Process IDentifier : le numéro de programme ( obtenu avec " ps -f " ) par défaut le message est 15 et le programme doit prévoir de s'arreter proprement dans ce cas. option -1 pour arrĂȘter un shell de connection option -9 si le programme ne s'arrĂȘte pas par kill PID trap 'commande' n piège le message envoyé par kill et exécute la commande à ce moment là. Permet d'interdire à l'utilisateur d'interrompre par [Ctrl] C trap "" 2 ( "" chaĂźne vide , 2 signal d'interruption) date [+"nous sommes en l'an %Y"] [ permet de choisir un format d'affichage ] touch fichier$(date +%F) ( crée un fichier daté du jour ) touch fichier$(( 9999999999 - $(date +%s))) ( crée un fichier numeroté en decroissant par secondes avant 2287 ) man command ( affiche l'aide en ligne pour la commande ) ssh [uti_dist@]serveur_dist date; date (compare la date sur un serveur distant et en local) pour éviter de saisir le mot de passe, ajouter le contenu du fichier local .ssh/id_???.pub sur le distant .ssh/authorized_keys pour générer une paire de clés sques/privées sh-keygen logger 'message' permet Ă  tout le monde d'Ă©crire dans /var/log/messages 8 - Les redirections Certaines commandes lisent ou écrivent des caractères : cat fichier lit les caractères du fichier et les écrit a l'écran a - Entrée et sortie standards le clavier et l'écran de la console b - Redirection d'entrée à la place du clavier définit dans quel fichier la commande doit lire commande < fichier ex : tr a-z A-Z < fichier affiche en majuscule le contenu du fichier ex : tr a-z A-Z <<< coucou affiche COUCOU commande < lit les lignes qui suivent comme un fichier jusqu'à la ligne commençant par FIN commande <<< chaîne de caractères ex : tr a-z 1-3 <<< abcde affiche 12333 diff fichier_loc <(ssh hote.distant cat fichier_dist) # pile FIFO en lecture sans espace entre < et ( c - Redirections de sortie à la place de l'écran définit dans quel fichier la commande doit écrire commande > fichier attention , cela efface l'ancien fichier du mĂȘme nom ex: cat > fichier écrit ce que l'on va taper au clavier dans un fichier pratique pour créer de petits fichiers pour recuperer aussi les messages d'erreur: commande &> fichier commande >> fichier ( rajoute à la fin du fichier ) ex : cat fich2 fich3 >> fich1 rajoute le contenu de fich2 et fich3 à la fin de fich1 d - Sortie d'une commande vers l'entrée d'un autre "|" # appelé un pipe ( [paĂŻpe] = tube ) ex : ls -l | less liste le répertoire en s'arr&ecric;tant à chaque page ex : cat fichier | lp pour imprimer un fichier protégé en lecture e - Tester si données en entrée find . -name toto 2> /dev/null | ifne -n echo "je n'ai pas trouvĂ© toto" # /dev/null est la poubelle ici pour mettre les erreurs 9 - Les tests A la fin de chaque commande, celle ci renvoie un code qui peut ĂȘtre testé. La variable ? contient le code retour de la dernière commande. Une commande qui s'éxécute sans erreur renvoi le code retour 0 (zero). ex: if grep ^toto: /etc/passwd > /dev/null then echo connu else echo inconnu fi idem: grep ^toto: /etc/passwd > /dev/null && echo connu || echo inconnu grep ^toto: /etc/passwd > /dev/null || echo -n in; echo connu On peut faire des tests complexes de plusieurs commande avec des opérateur logiques ( || pour ou, && pour et ) ex: grep ^toto: /etc/passwd && grep ^titi: /etc/passwd idem if grep ^toto: /etc/passwd then grep ^titi: /etc/passwd fi ( comme le shell est paresseux, la deuxième commande n'est exécutée que si la première a abouti et inversement dans le cas du || ) Bien sur cela ne suffit pas car en général, on désir tester autre chose que des résultats de commande. Pour cela il y a la commande test. test "$A" ( test si la variable A existe et est non vide ) test "$LOGNAME" = toto ( "" évitent une erreur si la variable est vide, espace autour de = ) test "$LOGNAME" != toto test $N -gt 10 ( plus grand que ) astuce pour eviter les négations, il peut ĂȘtre util de ne rien faire ( commande ":" ) je cherche les fichiers qui ne contiennent pas toto for i in * do if grep toto $i > /dev/null then : else echo "$i ne contient pas toto" fi done Pour gérer plusieurs alternatives : case $VAR in a) echo "$VAR vaut a"" ;; b|c) echo "$VAR vaut b ou c" ;; *) echo "$VAR vaut n'importe quoi" esac les ";;" c'est pour dire d'ignorer les cas suivants 10 - Les boucles until commande1 do commande2 done # tant que commande1 plante, commande2 est exécutée while commande1 do commande2 done # tant que commande1 n'envoie pas d'erreur, commande2 est exécutée cat fichier | while read i j k l do echo "la premiere colonne = $i" done for i in toto titi tata; do echo $i; done # pour la suite d'entiers de 10 à -2 for i in {10..-2}; do echo $i; done # aussi pour les lettres echo alphabet : {A..Z}

options utiles pour rendre les scripts plus robustes:
    #!/bin/bash
    set -euo pipefail
    IFS=$'\n\t'
cf : http://redsymbol.net/articles/unofficial-bash-strict-mode
copie locale
-e # pour arrĂȘter le script si une commande (sauf dans un teste) renvoie une erreur (attention aux grep)
-u # arrĂȘte le programme en cas de refference Ă  une variable non dĂ©finie ( ex coquille sur le nom )
# ci-dessous non pas toujours pertinante ( exemple si utilisation grep -i toto liste_de_noms || echo inconnu )
-o pipefail # sinon dans un enchainement de commandes "tubées" seul le dernier code est pris en compte

une fonction utilse pour finir proprmement:
    #!/bin/bash
    function sortie {
      # ici on reange le bazarre
    }
    trap sortie EXIT
cf : http://redsymbol.net/articles/bash-exit-traps
copie locale

certaines commandes ont des comportement etranges mais explicables:
https://www.pixelbeat.org/docs/coreutils-gotchas.html
copie locale

http://cb.vu/unixtoolbox.xhtml copie locale
Advanced Bash-Scripting Guide copie locale

ƒraηcois✉memoρersο.ƒr