====== Bash et commandes basiques ====== Voici un **petit** nombre de commandes unix qui couvriront 90% de vos besoins à long terme! Pas besoin d'en connaitre toutes les variantes, surtout pas. Il est souvent bien assez efficace de combiner deux commandes simples plutôt que de recherche une option qui permettrait de le faire en une commande. De toute façon s'il s'agit d'optimiser réellement, le shell n'est pas souvent la meilleure option... La productivité passe généralement en priorité! La majorité des commandes comprend l'argument ''%%--%%help'' pour afficher un résumé moins verbeux que ''man commande''. Pour rechercher une commande on peut utiliser ''man -k motclé'' (k=keyword), ou ... google, ou https://die.net ... Voyez enfin [[https://explainshell.com/explain?cmd=for%20user%20in%20%24%28cut%20-f1%20-d%3A%20/etc/passwd%29%3B%20do%20crontab%20-u%20%24user%20-l%202%3E/dev/null%3B%20done|explain shell]] pour un déchiffrage d'une commande bash composée, bien utile pour apprendre. ==== Langage bash ==== ^ Commande ^ Usage ^ | ''#''... | Commentaire (sauf si entouré de guillemets etc) | | cmd ''&'' | Commande lancée en tache de fond, voir ''bg'', ''fg'' ci-dessous | | '';'' | Séparateur d'instruction, à défaut d'un retour à la ligne | | cmd1 ''|'' cmd2 | Enchainer le stdout (et non pas stderr!) de la commande de gauche dans le stdin de celle de droite. Utilisez ''cmd1 2>&1 | grep elt'' pour filter stdout et stderr. | | ''&&'', ''||'' | Enchainer les commandes ''cmd && echo ok'' ("et": si cmd réussit), ou bien ''cmd || echo failed'' ("ou": si cmd échoue) | | cmd ''>'' fichier | Rediriger la sortie "stdout". Utiliser ''2>'' pour rediriger la sortie d'erreur. Spécial: ''&>'' (stdout+stderr) ou ''2>&1'' (stderr dans stdout). Et donc ''cmd &> /dev/null'' pour rendre une commande totalement silencieuse, même en cas d'erreur | | cmd ''<'' fichier | Envoyer le contenu du fichier dans l'entrée de la commande. Souvent équivalent optimisé de ''cat fichier | cmd'' | | ''$''var | Plus sûrement écrit ''"$var"'' (qui, lui, respecte les espaces): remplacé par le contenu de la variable. Pour un texte littéral écrire '' '$var' '' (bash n'interprête plus rien). Spécifier ''${var}'' si ambigü: ''echo "${HOME}aa"''. | | ''$HOME'' | Dossier 'home" de l'utilisateur en cours (aussi noté ''~'') | | ''$PATH'' | Chemins des exécutables séparés par '':''. Ajoutez les votres à la fin, pas au début, et jamais ''.'' Ex. ''export $PATH="$PATH:$HOME/bin"'' | | ''$('' cmd '')'' | Remplacé par le résultat de la commande: ''echo "I am $(whoami)"''. Anciennement écrit ''`cmd`'' (backquotes) | | ''for'' f ''in'' a b c''; do'' ... ''done'' | Répéter ''...'' avec ''f="a"'' puis ''f="b"''... Ex. ''for f in *.bak; do echo "Depl $f"; mv $f /tmp; done'' | | ''if'' tst1 ''; then'' cmd1 ''; elif'' tst2 ''; then'' cmd2 ''else'' cmd3 ''; fi'' | Si ''tst1'' (une commande) est évaluée positivement, executer ''cmd1'' sinon si ''tst2'' est positif, excéuter ''cmd2'' sinon exécuter ''cmd3''. Exemple: ''if grep erreur /var/log/fichier.log; then exit; fi''. Voyez aussi ''case'' ... ''esac'' qui a ses avantages. | | ''while'' cmd''; do'' ... ''done'' | Boucler ''...'' si ''cmd'' est vraie | | ''$?'' | Le code d'erreur retournée par la dernière commande (0=positif, autres=erreur): ''rm fic; [ "$?" != 0 ] && echo Echec'' | | ''$#'' | Le PID du script en cours | :!: Voyez ci-après les "conditions" en bash, notamment l'utilisation de ''%%[[%% ... %%]]%%''. ==== Fichiers et dossiers ==== ^ Commande ^ Usage ^ | echo | Affiche un texte (echo "Bonjour"). Pour les adeptes du C, on peut aussi utiliser ''printf "Cou%s\n" "cou"''. | | mv | Déplacer un fichier | | cp | Copier un fichier, souvent avec ''-a'' pour conserver les droits et propriétés | | cd | Changer de dossier actuel (utilisez ''cd -'' pour basculer entre deux dossiers) | | pwd | Print working directory: le dossier courant. Mieux: ''export PS1='\u@\h:\w #' '' | | ls | ''ls -AlF'' très utile, à mettre en alias | | tree | A installer (''apt install tree''), affiche une arborescence en texte | | mkdir | Créer un dossier, récursivement avec ''mkdir -p /tmp/sub1/sub2/sub3/dir'' | | dirname, basename | extraire le chemin ou le dernier élément d'un fichier. ''[ $(basename $HOME) = $(whoami) ] && echo "Vous êtes à la racine de votre dossier personnel"'' | | tar | Compresser ''tar cvzf archive.tgz fichiers'' et décompresser avec ''xvfz'' (create/extract) | | rsync -a | Copier seulement les différences (bien plus efficace que scp): ''rsync -a %%--%%delete %%--%%dry-run ...'' pour tester sans risque, ''%%--%%info=progress2'' pour voir la progression | | find -exec | Cherche: ''find /var/log -type f -name '*.gz' -mtime +31 -exec rm {} ';' '' | | which | Donne le chemin vers un exécutable | | locate | Trouve un fichier dans le système | | ln -s | Lien symbolique (fichier ou dossier: ''ln -s source destination''). Toujours avec ''-s''! | | touch | Mettre a jour la date d'un fichier, ou le créer vide | | inotifywait | Déclencher une action lors d'un changement dans un dossier | ==== Contenus et traitements ==== ^ Commande ^ Usage ^ | echo | Afficher une chaine de caractères, utiliser les doubles quotes pour étendre les variables, de simples quotes pour du littéral, et des accolades pour "protéger" le nom de variables: ''echo "${HOME}is my" sweet '$HOME' '' | | less | Utiliser ''/motclé'' pour rechercher puis ''n'' ou ''shift+n'' pour naviguer. Et ''90g'' pour aller à une ligne donnée. ''q'' pour quitter less. | | tail -F | Affiche en continu la fin d'un fichier, même s'il est recrée | | grep -i | Rechercher du text (cf ''%%--%%color'' bien pratique, ''egrep'' pour des regex avancées, ''fgrep'' pour du texte pur). ''grep -v'' pour inverser le filtre. | | tee -a | dupliquer stdout dans un fichier | | diff | ''diff -y'' affiche les différences entre deux fichiers cote à coté | | cat -n | Afficher un contenu. Ou simplement ''cat > nouveaufichier.txt'', coller/saisir son texte, puis ''control-d'' pour terminer. Une façon très efficace de créer ou ajouter à un fichier. | | cut | En caractères (''cut -c1-8'') ou en field avec délimiteur (''cut -d: -f1,3-4'') | | tr | "translitterate": ''tr / _'' pour remplacer une lettre, ou ''tr -d ':' '' pour l'enlever | | sed | "Traitement de texte mode unix": ''sed -i s@rech@rempl@g fichier'' (s=subsitute, g=global), ''ps|sed -n '/bash/s|\s*\(.*\) pts/[0-9: ]*\(.*\)|\2: \1|p''' | | awk | Langage bien plus clair que sed pour les traitements un peu complexes ou pour de vrais calculs numériques. ''df -BG -l -t ext4| awk '{sum += $4} END {print sum "GB free"}' '' | | sort | Tri, ordonnancement (un peu piégeux), utile aussi avec ''uniq'' | ==== Divers et bash ==== ^ Commande ^ Usage ^ | !cmd | Ré-exécuter la dernière commande qui commençait par "cmd" | | history | Voir l'historique, souvent avec ''history | grep macommande'' | | control k | Effacer la ligne à droite du curseur | | alias | Ex. ''alias syslog="tail -F /var/log/syslog"'' ou ''alias hgrep='history|grep' '', ''alias ..='cd ..' '' très utiles à ajouter dans son ''$HOME/.bashrc'' | | bash -eux monscript.sh | Lancer un script en mode verbeux (''x'') et arrêt sur la première erreur (''e'') ou variable non déclarée (''u''). Mieux: commencez votre script avec ''#!/bin/bash -feux -o pipefail'' | | vi | Utilisez ''vipw'', ''vigr'', ''visudo'' pour les fichiers respectifs (passwd, groups, sudoers). Commandes '''' puis ''u''=undo, ''cw'' change word, ''d$'' delete to end of line, ''J''=join... Utilisez '''' suivi de '':q!'' pour sortir (quit) sans sauvegarder vos modifications. Voyez ci-après le paragraphe dédié. | | printf | Permet un formatage à la C, souvent bien pratique et plus clair: ''printf "% -20s: %.2f\n" Element 123.456'' | | xargs | Ex: ''ls|grep -v zip|xargs rm'' supprimme tous les fichiers locaux, sauf les zip. Et ''ls *.txt | xargs -I@ mv @ @.bak'' est mieux et moins verbeux que ''ls *.txt | while read f; do mv $f $f.bak; done''. | ==== Gestion de process ==== ^ Commande ^ Usage ^ | fg, bg et jobs | Apres un ''control-z'' (process suspendu), ''bg'' pour le passer en background, ''jobs'' pour lister les processes, ''fg'' pour repasser en foreground. ''control-c'' pour le tuer. | | ps | Monter les process en cours, ex avec un ''ps aux | grep macommande'' | | kill | Tuer un process par son PID (ou le job 2 avec ''kill %2'') | | pkill | Tuer un process via son nom ''pkill bash'' (oups) | | nohup | No hang up: ''nohup commande &> log.txt &'' ne sera pas tuée par la fin de session | ==== Réseau et observation ==== ^ Commande ^ Usage ^ | ssh | Se logguer à distance | | ssh-add | Laisse son "agent" se souvenir d'une passphrase protégeant une clé, pour ne pas avoir à la saisir à chaque fois | | curl | Faire du GET ou du POST vers une adresse web | | netstat | ''netstat -tanp'' affiche les service IP en cours, ou plus moderne: ''ss -ltp'' | | iperf3 | Client et serveur: calculer une bande passante | | ping | Voir si un serveur ou une adresse IP répond (sans garantie parfaite car il peut refuser). Si ''nc'' existe, c'est plus efficace de faire un ''nc -zw $tmout $srv $port'' | | tracepath | Equivalent au vieux traceroute, vers un serveur ''tracepath -4b free.fr'' | | df -hl | "Disk free" en mode long et "h"umain | | du -sh * | Occupation disque des éléments du dossier en cours | | NMON=mcdn nmon | moniteur de ressources, configuré pour memory, cpu, disks, network. Remplace ''htop'', ''iftop'', ''iotop'' ... On peut utilement placer le ''export NMON=mcdn'' dans son ''.bashrc''. | ==== Utilisateurs et droits ==== ^ Commande ^ Usage ^ | sudo | Exécuter une commande en tant que ''root'' (voir ''visudo'' ou le groupe ''sudoers'') | | su | En étant root, pour devenir un utilisateur (''su - normaluser''). Cf. aussi ''runuser -u username commande'' | | adduser | ou le minimaliste useradd [[doc:formations:hebergement:serveur:proteger#utilisateurs|ref.]] | | chmod | Changer des droits: ''chmod -R go-w mondossier'' ou ''chmod u+x monexec'' | | chown | Nouveau propriétaire ''chown jeremie ~/.ssh/*'' | | chgrp | Nouveau groupe ''chgrp adm fichiersensible'' (cf. aussi combiné ''sudo chown -R www-data:www-data /var/www'')| ==== Admin / système ==== ^ Commande ^ Usage ^ | apt | ''install'' pour installer, ou ''update, upgrade, dist-upgrade'' pour mettre à jour le système | | service | ''status|stop|start|restart'' gère les "daemons": ''service apache2 restart'' | | mount | (bas niveau) Monter un device sur un dossier (point de montage): ''mount /dev/sdd1 /tmp/cléusb''. Démonter avec ''unmount''. Cf. aussi ''blkid'' et ''lsblk''. Notez le pratique ''tmpfs /volatile tmpfs nodev,nosuid,noexec,nodiratime,size=512M 0 0'' dans /etc/fstab pour se faire un "ramdisk" rapide et volatile, monté avec ''mount /volatile'' une fois le dossié crée. | | sshfs | Monte un dossier distant localement: ''sshfs root@srv.com:/etc /tmp/remote_etc'' | | mysql | ''mysql -u root %%--%%database DB'' ouvre un shell SQL | | ip | Configuration du réseau: ''ip a'' ou ''ip route'' | ===== Parenthèses, crochets et accolades ===== * ''( … )'': permet d'enchainer des commandes à l'intérieur d'un sous-shell, dans un process séparé: les assigations de variables et redirections faites à l'intérieur n'impacteront pas l'extérieur! ''x=1; (x=2); echo $x'' retourne 1 et non pas 2! * ''{ … }'' les crochets servent aussi à regrouper des commandes, mais cette fois ci dans le même process: ainsi ''x=1; {x=2}; echo $x'' donne cette fois-ci bien 2. C'est peu utilisé en pratique. * ''$( … )'' est une substitution de commande. La sortie ''stdout'' des commandes exécutées à l'intérieur des parenthèses se substitue à l'expression: ''echo "Aujourd'hui nous sommes le $(date)"'' * ''$%%((%% … %%))%%'' retourne la valeur de l'expression arithmétique. Attentions, seuls les nombres entiers sont gérés par bash! * ''${ … }'' permet d'étendre un paramètre: soit avec sa valeur, soit avec l'une des très nombreuses opérations possibles de bash en la matière. Citons par exemple * ''${a-ABC}'' qui retourne la valeur de la variable ''a'' si elle est définie et ABC sinon (valeur par défaut) * ''${a: -4}'' qui retourne les 4 derniers caractères de la variable ''$a'' * ''{a#prefix}'' ou ''{a%suffix}'' pour éliminer un début ou une fin de chaîne de caractères... * ''%%[[%% … %%]]%%'' explicitent les conditions: * avec un préfixe, par exemple * ''%%[[%% -n $a %%]]%%'' pour tester l'existence de la variable * ''%%[[%% -f /etc/file.conf %%]]%%'' pour celle d'un fichier * avec un triplet: * ''%%[[%% "$s1" == "abcd" %%]]%%'' compare des chaines de caractères, mais attention car une partie droite sans guillemet forme un pattern: * ''%%[[%% $var == "ab*" %%]]%%'' teste l'égalité à la chaine exacte ''ab*'' * mais ''%%[[%% $var == ab* %%]]%%'' teste si la variable ''var'' //commence// par ''ab'' * on peut utiliser des parenthèses, ainsi que les classiques négation ''!'', conjonction ''&&'' et disjonction ''||'' * :!: conservez bien un espace entre chacun des éléments de l'expression ! * ''[ … ]'' est historiquement la façon d'encoder des conditions et qui reste davantage portable que les doubles crochets. En bash elle est obsolète, d'autant qu'elle présente davantage de pièges: à éviter. En fait ''/usr/bin/['' est une commande tout comme ''test'' ! A noter, fonctionellement, ''test -f fic'' est quasiment équivalent à ''[ -f fic ]'' et à ''%%[[%% -f fic %%]]%%''. Exemple: if [[ "${newfile: -4}" = ".jpg" ]] || [[ "${newfile: -5}" = ".jpeg" ]] then [[ $(identify -format %m "$newfile") != 'JPEG' ]] && echo "Le fichier $newfile est nommé en JPEG mais ne c'est pas un JPEG !" fi fi ===== Eléments spécifiques à bash ===== Plus de commandes et gestion de l'historique sur [[https://www.howtogeek.com/465243/how-to-use-the-history-command-on-linux/|cette page]] (''Control-R'': rechercher, ou ''!debutcmd:p'' pour confirmation...) Un "heredoc" avec remplacement de variables, très pratique pour générer de grosses sections de configuration, ou pour gérer facilement des quotes hétérogènes sans devoir recourir à ''\"'' par exemple: cat > fichier.cfg < Déclarer une fonction (même syntaxe que sh) monquit() { echo "$(date): arguments: $1 $2" exit } monquit "Succès" "fichier ok" Usage du ''IFS'' "internal field separator" et d'un "herestring" ''%%<<<%%'' pour extraire efficacement les deux valeurs 0000 et 0021 du nom du fichier (moins gore que deux ''sed''?). IFS='-.' read -r dummy1 x y dummy2 <<< "tileshp/contours-0000-0021.shp" Autres commandes bash utiles: * ''trap'' (routine en cas d'erreur), * ''flock'' (zone critique à ne pas exécuter en même temps qu'un autre process ou soi-même plusieurs fois)... ====== Les éditeurs vi et vim ====== Certains préfèreront utiliser ''nano'' qui est plus intuitif mais vraiment plus limité que "vi". Ce dernier est dur à maintriser mais il est présent partout et il est en fait extrêmement puissant. Voici donc quelques fonctions utiles dans ''vi'' (à saisir après la touche '''') Générique * '':q!'' quit (meme s'il y a des modifications) * '':wq'' write and quit * ''*'' rechercher le mot lu sous le curseur * ''/rech'' pour rechercher, ''n'' pour next, ''N'' pour précédent (idem ''less'') * ''8G'' aller à la ligne 8 (idem ''less'') Edition * ''u'' undo (répétable) * ''i'' insert (''I'' pour insérer en début de ligne) * ''a'' append (''A'' pour ajouter en fin de ligne) * ''o'' nouvelle ligne au dessous (''O'' pour une nouvelle ligne au dessus) * ''J'' pour joindre la ligne qui suit à celle sous le curseur * ''d?'' pour "delete", où ''?'' en précise la portée: * ''dd'' pour la ligne * ''d$'' jusqu'à la fin de ligne * ''d^'' vers la gauche (tapez ''d^ '') * ''dw'' (delete word, et ''3dw'' supprime 3 mots, vous voyez la logique implacable?)... * ''r?'' pour "replace", avec la même logique que le ''d'' * ''c?'' pour "change" (delete+insert), suivi comme ci-dessus * ''cc'' change line (donc ''5cc'' pour changer 5 lignes d'un coup) * ''c$'' remplace toute la fin de ligne (idem que ''C'') * ''c^'' remplace tout le début de ligne * ''cw'' change word ... * ''yy'' yank line (copie de la ligne courante), ''yw'' copie du "word" sous le curseur, etc ... * ''p'' paste (coller le contenu du "y", à droite du curseur) * ''w'' beginning of next word, ''e'' end of next word Avancé * ''control O'' et ''control I'' rejouer les positions successivement suivies * '':%s/rech/rempl/gc'' pour remplacer avec demande (aaaarg) * '':r!CMD'' ajouter le résultat de la commande CMD (ex. '':r!date'') * '':%!cat -n'' numéroter toutes les lignes * '':,$d'' détruire du curseur jusqu'à la fin du fichier Couper-coller (''vim'' et pas ''vi'') * ''V'' initie la zone à copier/couper en surbrillance ... * puis ''d'' pour la couper (delete), ou bien ''y'' pour la copier (yank) * enfin ''p'' la colle après le curseur (''P'' pour avant le curseur) ====== Fichiers SSH et journaux importants ====== ^ Variable ou fichier ^ Intérêt ^ | /var/log/syslog | Journal système principal. Ex. ''tail -F /var/log/syslog'' pour le voir "en live" | | /var/log/auth.log | Journal des tentatives d'identifications | | /etc/cron/cron.* | Taches récurrentes | | /var/log/nginx/access.log | Journal par défaut du serveur web (si c'est ''nginx'') | | ~/.ssh/authorized_keys | Les clés publiques (une par ligne) qui permette d'accès au compte | | ~/.ssh/config | Alias et raccourcis pour ses accès SSH (très pratique!) | | /etc/ssh/sshd_config | Configuration du serveur SSH | ====== Outils annexes en ligne de commande ====== Il existe réellement des milliers d'outils, écrits dans toutes sortes de langages ou de scripts (exécutables/binaires, python, PHP...) Certains sont très classiques, comme ceux mentionnés ci-avant (les ''cut'', ''sed'', ''grep'' ...). D'autres le sont moins mais reste très utiles. On peut citer * ''jq'' pour exploiter du JSON (et [[https://github.com/kellyjonbrazil/jc|jc]] pour convertir des sorties de commande unix en json) * ''mlr'' (miller) pour du CSV (ou la suite [[https://csvkit.readthedocs.io/en/latest/|CSVkit]], dont ''in2csv'' pour convertir du Excel) * ''datamash'' pour des calculs sur des tables (ex. calculer la médiane des colonnes d'un fichier CSV). * ''gnuplot'' pour créer des graphiques (non trivial!) * [[https://github.com/cactusdynamics/wesplot/tree/main|wesplot]] permet de tracer en live un résultat d'un pipe linux Pour un usage orienté "data science", vous pouvez aussi consulter [[https://jeroenjanssens.com/dsatcl/chapter-2-getting-started.html|ce site]], plutôt bien fait. N'hésitez pas à recourir à Python non plus, qui fonctionne aussi en ligne de commande si besoin. Il existe aussi des versions améliorées ou plus rapides d'outils, comme pour la recherche de fichiers ou de contenu avec [[https://github.com/sharkdp/fd|fdfind]] ou [[https://github.com/BurntSushi/ripgrep|ripgrep]] ... Il ne s'agit bien sûr pas de les connaître tous mais bien de s'en approprier assez, pour qu'une fois combinés ils vous permettent de régler 99% de vos besoins. Vous croiserez bien sûr de nouvelles fonctions tout le temps, des "raccourcis" plus rapides ou plus pratiques, rien ne presse. Veillez cependant à n'utiliser que des outils reconnus, car il est toujours risqué d'installer un exécutable qui provient d'une source peu connue ou non officielle (typiquement les fonctions qui ne sont pas disponibles via ''apt'').