====== 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