====== Bash ====== * [[linux:zsh|ZSH]] * [[https://connect.ed-diamond.com/Linux-Pratique/lp-124/optimiser-sa-configuration-de-bash|Optimiser sa configuration de Bash]] * [[https://github.com/dylanaraps/pure-bash-bible]] * [[http://aral.iut-rodez.fr/fr/sanchis/enseignement/IntroProgBash_2022-06-03.pdf|Introduction à la programmation en Bash]] * [[https://mywiki.wooledge.org/ParsingLs|Why you shouldn't parse the output of ls(1)]] * [[https://connect.ed-diamond.com/linux-pratique/lp-133/rendre-ses-scripts-bash-plus-fiables|Rendre ses scripts « Bash » plus fiables]] * [[https://nochlin.com/blog/6-techniques-i-use-to-create-a-great-user-experience-for-shell-scripts|6 Techniques I Use to Create a Great User Experience for Shell Scripts]] * [[https://blog.smarchal.com/bash-substitutions-variables|Les substitutions de variables en bash]] ==== Utiliser les arguments de la commande précédente ==== [[https://stackoverflow.com/questions/3371294/how-can-i-recall-the-argument-of-the-previous-bash-command/3371711|Source]] Utiliser ''Alt+.'' ==== Lire ligne par ligne ==== === Un fichier === while read variable; do echo $variable done < fichier.txt for p in $(cat dico); do echo $p done La boucle ''for'' lit mot par mot alors que la boucle ''while'' lit vraiment ligne par ligne. === Une commande === On peut utiliser la substitution de commande: while read f do echo $f done < <(ls) ==== Substitution de commande ==== //command substitution// ou //process substitution// * [[https://unix.stackexchange.com/questions/17107/process-substitution-and-pipe]] * [[https://askubuntu.com/questions/678915/whats-the-difference-between-and-in-bash]] La syntaxe ''<(commande)'' renvoie le chemin vers un fichier contenant la sortie de la commande ''commande'' (cela semble être un tube anonyme). On peut donc faire des choses comme ça: cat <(date) # lit le contenu du fichier cat < <(date) # redirige le contenu du fichier vers l'entrée standard de cat ==== Conditions ==== * [[https://fr.wikibooks.org/wiki/Programmation_Bash/Tests]] * [[https://openclassrooms.com/fr/courses/43538-reprenez-le-controle-a-laide-de-linux/43394-les-conditions]] * [[https://jmmv.dev/2020/03/test-bracket.html|test, [, and [[]] if [ $1 -ge 20 ] then echo "Vous avez envoyé 20 ou plus" else echo "Vous avez envoyé moins de 20" fi if [ "$1" != "-n" ] then echo "Do something" fi === Si une chaîne de caractère commence par un motif === [[https://stackoverflow.com/questions/2172352/in-bash-how-can-i-check-if-a-string-begins-with-some-value]] [[ $a == z* ]] # True if $a starts with a "z" (wildcard matching). [[ $a == "|"* ]] # True is $a starts with a "|" (| is a reserved symbol, so quoting it is mandatory) [[ $a == "z*" ]] # True if $a is equal to z* (literal matching). === Suivant le nombre de lignes retournées par une commande === if [ `commande | wc -l` -eq 0 ] then commande fi === Si une variable est définie === [[https://www.cyberciti.biz/faq/unix-linux-bash-script-check-if-variable-is-empty/|Source]] if [ -z "$var" ] then echo "\$var is empty or not defined" else echo "\$var is NOT empty" fi Pour tester à la fois la définition et le contenu: if [ "${var}" == "1" ]; then echo "var = 1" fi Pour une variable d'environnement: if [[ -z "${DEPLOY_ENV}" ]]; then === Si une variable contient un motif === if [ `echo $var | grep -c "motif"` == "0" ]; then echo "Pas de motif" else echo "Trouvé !" fi === Si un fichier existe === Ou n'existe pas : if [ ! -e tasks.csv ] then rec2csv -d ";" tasks.rec > tasks.csv fi === Négation === if [ ! -e ".git" ] echo "Git folder doesn't exist" fi === Comparer deux dates === [[https://unix.stackexchange.com/questions/84381/how-to-compare-two-dates-in-a-shell|source]] todate=$(date -d 2013-07-18 +%s) cond=$(date -d 2014-08-19 +%s) if [ $todate -ge $cond ]; then break fi ==== Renommer tous les fichiers d'un dossier ==== for file in *; do mv $file `echo $file | cut -d . -f 5`-VOSTFR.avi; done ==== Conserver les retours à la ligne en affichant une variable ==== Mettre la variables entre guillemets: echo "$var" ==== Rediriger les flux de sortie ==== [[https://askubuntu.com/questions/625224/how-to-redirect-stderr-to-a-file|Source]] * rediriger ''stderr'' vers ''stdout'': ''2>&1'' * tout rediriger vers un fichier: ''&> file'' === Rediriger un groupe de commandes ==== { cmd1 cmd2 } > redirect.log ==== Variables particulières ==== === Les variables des paramètres === [[https://openclassrooms.com/fr/courses/43538-reprenez-le-controle-a-laide-de-linux/43126-afficher-et-manipuler-des-variables#/id/r-43089|Source]] * ''$#'' contient le nombre de paramètres * ''$*'' contient tous les paramètres * ''$@'' contient tous les paramètres * ''$0'' est le nom du script * ''shift'' permet de décaler les paramètres. ''$*'' et ''$@'' sont identiques si ces variables ne sont pas utilisées entre guillemets: elles contiennent tous les arguments, lorsque plusieurs mots étaient entre guillemets pour former un unique paramètre, ces guillemets sont supprimés et tous les mots composants les paramètres sont considérés indépendants. ''"$*"'' contient tous les paramètres, mais considérés comme un unique paramètre; ''"$@"'' conserve les paramètres comme fournis en entrée ([[https://stackoverflow.com/questions/22589032/what-is-the-difference-between-and/22589151|source]]). # Si on exécute ce script avec ./script.sh "Hello World" Foo Bar rm $* # rm: cannot remove ‘Hello’: No such file or directory # rm: cannot remove ‘World’: No such file or directory # rm: cannot remove ‘Foo’: No such file or directory # rm: cannot remove ‘Bar’: No such file or directory rm $@ # rm: cannot remove ‘Hello’: No such file or directory # rm: cannot remove ‘World’: No such file or directory # rm: cannot remove ‘Foo’: No such file or directory # rm: cannot remove ‘Bar’: No such file or directory rm "$*" # rm: cannot remove ‘Hello World Foo Bar’: No such file or directory rm "$@" # rm: cannot remove ‘Hello World’: No such file or directory # rm: cannot remove ‘Foo’: No such file or directory # rm: cannot remove ‘Bar’: No such file or directory === Autres variables === * ''$?'' renvoie le code de retour de la dernière commande exécutée * ''$$'' est le PID du programme actuel ==== Savoir si le script est lancé en tant que root ==== [[https://www.cyberciti.biz/tips/shell-root-user-check-script.html|Source]] if [ "$(id -u)" != "0" ]; then echo "This script must be run as root" 1>&2 exit 1 fi ==== Connaître l'utilisateur derrière sudo ==== [[https://stackoverflow.com/questions/3522341/identify-user-in-a-bash-script-called-by-sudo|Source]] user=${SUDO_USER:-$(whoami)} ==== Booléens ==== [[https://stackoverflow.com/questions/2953646/how-can-i-declare-and-use-boolean-variables-in-a-shell-script]] the_world_is_flat=true # ...do something interesting... if [ "$the_world_is_flat" = true ] ; then echo 'Be careful not to fall off!' fi ==== Système d'options ==== [[http://linuxcommand.org/lc3_wss0120.php]] set -u while [ $# -gt 0 ]; do case $1 in -f | --file ) shift filename=$1 ;; -i | --interactive ) interactive=1 ;; -h | --help ) usage exit ;; * ) usage exit 1 esac shift # inutile ? done ==== Opérations arithmétiques ==== [[https://linuxize.com/post/bash-increment-decrement-variable/]] i=$((i+1)) ((i=i+1)) let "i=i+1" ((i+=1)) let "i+=1" ((i++)) ((++i)) let "i++" let "++i" ==== Connaître le chemin d'un script ==== [[https://stackoverflow.com/questions/4774054/reliable-way-for-a-bash-script-to-get-the-full-path-to-itself|Source]] SCRIPTPATH="$( cd "$(dirname "$0")" ; pwd -P )" ==== Boucles ==== Sur i: for i in $(seq 0 5); do echo $i; done # de 0 à 5 compris for i in 0 25 50 75 100 125 150 175 200 225 250 275 300; do echo $i; done # équivalent à: for i in $(seq 0 25 300); do echo $i; done # Possibilité de factoriser: s=$(seq 1 10) for c in $c; do echo $c; done i=1 while [ $i -le 2048 ] do echo $i; i=$((i*2)) done ==== Tableaux ==== * [[https://www.linuxjournal.com/content/bash-arrays]] a=("foo" "bar") for item in ${a[*]} do echo $item done === Ajouter un élément === [[https://linuxhint.com/bash_append_array/|Source]] a=() a+=("foo") === Inverser un tableau === [[https://unix.stackexchange.com/questions/412868/bash-reverse-an-array|Source]] incremental_backups=$(echo "${incremental_backups_rev[@]} " | tac -s ' ') ==== Chaînes de caractères ==== === Enlever le dernier caractère === [[https://unix.stackexchange.com/questions/144298/delete-the-last-character-of-a-string-using-string-manipulation-in-shell-script|Source]] foo="abcde" echo "${foo::-1}" # abcd === Enlever un préfixe === [[https://stackoverflow.com/questions/16623835/remove-a-fixed-prefix-suffix-from-a-string-in-bash|Source]] v="/data/truc/foo" prefix="/data/truc/" echo ${v#"$prefix"} ==== Chronométrer un programme ==== [[https://unix.stackexchange.com/questions/52313/how-to-get-execution-time-of-a-script-effectively|Source]] # Précision à la seconde: start=`date +%s` stuff end=`date +%s` runtime=$((end-start)) # Précision sous la seconde: start=`date +%s.%N` stuff end=`date +%s.%N` runtime=$( echo "$end - $start" | bc -l ) ==== Commentaires multi-lignes ==== [[https://stackoverflow.com/questions/43158140/way-to-create-multiline-comments-in-bash|Source]] : ' This is a very neat comment in bash ' ==== Générer un nombre aléatoire ==== * [[https://stackoverflow.com/questions/1194882/how-to-generate-random-number-in-bash]] echo $((1 + $RANDOM % 10)) od -t u -N 4 /dev/urandom | head -n 1 | cut -f 2 -d ' ' ==== Options Bash ==== === Récupérer le code de retour dans un pipe === Pour récupérer le code de retour de la première commande qui échoue dans un pipe ([[https://unix.stackexchange.com/questions/14270/get-exit-status-of-process-thats-piped-to-another|source]]) : set -o pipefail gcc ... 2>&1 | tee out res=$? === Ne pas développer * === Pour éviter que ''*'' soit remplacé par tous les fichiers et dossiers du dossier courant, lancer ''bash -f'' ([[https://stackoverflow.com/a/13484149|source]]). === Quitter à la moindre erreur === set -e === Changer des options pour une portion de script === Mettre la portion entre parenthèses ([[https://stackoverflow.com/questions/74525090/bash-set-x-only-for-the-duration-of-a-function|source]]) : #!/bin/bash set -eu ( set -o pipefail set +e false | cat echo "after $?" ) echo "before second" false | cat echo "after $?" false echo "sould not print" ==== Couleurs ==== Changer la couleur du texte affiché : * [[https://www.shellhacks.com/bash-colors/|Bash Colors]] Visualiser le rendu de toutes les couleurs ([[https://askubuntu.com/questions/27314/script-to-display-all-terminal-colors|source]]) : for x in {0..8}; do for i in {30..37}; do for a in {40..47}; do echo -ne "\e[$x;$i;$a""m\\\e[$x;$i;$a""m\e[0;37;40m "; done; echo; done; done; echo "" msgcat --color=test