bonjour à tous,
Un peu comme cuisiner demande de savoir des bases ;
je vais tenter de centraliser ici les trucs et astuces, les canevas de code, les choses répétitives à connaître en bash...
bonne lecture !
----------------------------------------------------------
je pense qu'on sera tous d'accord sur le
premier truc à faire pour apprendre le bash :
man bash
pour une aide d'une fonction, dans un terminal, tapez :
[fonction] --help
chmod --help
voire
[fonction] -help
[fonction] -h
qui ne sont pas bonnes mais qui déclencheront l'explication pour avoir l'aide
astuce :
apropos... je n'en dirais pas plus ! 😛
apropos video
quoi que j'écrive cela a sûrement été évoqué et mieux expliqué sur une de ses pages :
une réponse dans un post pour faire son premier Bonjour Monde
https://doc.ubuntu-fr.org/tutoriel/script_shell
https://doc.ubuntu-fr.org/wiki/glossaire
https://doc.ubuntu-fr.org/bash
https://abs.traduc.org/abs-fr/
http://aral.iut-rodez.fr/fr/sanchis/enseignement/bash/index.html
http://mywiki.wooledge.org/BashGuide
http://wiki.bash-hackers.org/
http://wiki.bash-hackers.org/scripting/obsolete
http://www.c-sait.net/cours/bash.php
https://www.gnu.org/software/bash/manual/html_node/index.html
http://www.abrillant.com/doc/linux/index.html
http://www.tldp.org/LDP/abs/html/index.html
https://linoxide.com/linux-how-to/lesser-known-linux-terminal-tricks/
pour vérifier du code :
http://www.shellcheck.net/
----------------------------------------------------------
Index
- Les Variables
- Afficher du texte sans s’embêter avec les quottes
- Les Calculs
- Les Variables en tableau
- version simple
- Des listes et des fichiers dans des tableaux
- version plus complète
- journaliser 1
- journaliser 2
- un splashscreen
- gestion des fichier ini / conf
- Les Conditions
- Les pipes
- Trim / FIFO
- être sudoer
- Les infos glanées sur ce fil
AJOUTS :
[tuto bash] changement valeurs dans un fichier texte
----------------------------------------------------------
Les Variables
sortir une partie d'une variable :
maVariable="un texte avec égale (=) en séparateur=des choses et d'autres"
echo "${maVariable}
${maVariable##*=} ; après le dernier =
${maVariable#*=} ; après le premier =
${maVariable%%=*} ; avant le premier =
${maVariable%=*} ; avant le dernier =
"
maVariable="PLEINS de mots eT dEs acCents âéèàç, espacEs... et des espaces à la fin"
echo "
${maVariable:0:3} ; 3 premiers caractères
${maVariable: -3:3} ; 3 dernier caractères
${maVariable: 10:3} ; 3 caractères depuis la 10 ème lettre
${maVariable: -10:3} ; 3 caractères depuis la 10 ème lettre depuis la fin
"
maVariable="PLEINS de mots eT dEs acCents âéèàç, espacEs... et des espaces à la fin "
echo "letexte est :
$maVariable
il fait ${#maVariable} caractères
---------------------------------------"
echo "Convertir espaces en underscore :
${maVariable//\ /_}
tout en minuscules
${maVariable,,}
tout en majuscules
${maVariable^^}
inverser minuscules et majuscules
${maVariable~~}"
supprimerLeDernierCaractere (){
local ligne="$@"
echo "${ligne:0:(( ${#ligne} - 1 ))}"
}
Afficher du texte sans s’embêter avec les quottes
Afficher une aide avec des caractères qui pourraient emmêler le code
afficher_aide () {
cat <<EOF
plein de texte ici avec des quottes ' et des doubles quottent "
qui ne seront pas considérées dans le code
EOF
}
afficher_aide
autre exemple envoyer du texte pour créer un script externe :
cat <<EOF > "$PWD/test"
#!/bin/bash
echo "bonjour monde"
echo "appuyer sur entrée pour continuer"
read r
EOF
chmod +x "$PWD/test"
Les Calculs
la syntaxe de bash ((X+Y))
((123+456))
((123*456))
...
sqrt() { echo -e "sqrt($1)" | bc -q -i; }
bc -l <<<"(sqrt(5))"
awk 'BEGIN { print 5.5+1.257; print sqrt(9); print (1-3)*2.5-sqrt(25); print 2**4,2^4,sqrt(2^4)}'
read -p "entrez un chiffre,nombre ?" nb; awk -v input="$nb" 'BEGIN {print sqrt(input)}'
avec apcalc
installation
sudo apt-get install apcalc
exemple
calc -p -- "(sqrt(5))"
Les Variables en tableau
quand on a du texte séparé par un ou plusieurs séparateurs, on a besoin de récupérer individuellement une ou des valeurs... comment se passer du cut :
version simple
Des listes et des fichiers dans des tableaux
#!/bin/bash
# ***********************************************************
echo "exemple 1
# prenons un fichier"
echo "une ligne
une autre ligne
une troisième
et de cat
miaou" > unFichier.txt
echo "# on va lire le fichier et mettre chaque ligne dans un index d'une variable"
# IFS=$'\n' une_liste=( $(cat unFichier.txt) )
IFS=$'\n' une_liste=( $(< unFichier.txt) ) # mieux comme ça !
echo "
# on sort les éléments un à un"
for uneLigne in ${une_liste[@]}
do
echo "${uneLigne}"
done
# ***********************************************************
echo ""
echo "exemple 2
# la même chose avec une liste directement"
une_liste="une ligne
une autre ligne
une troisième
et de cat
miaou"
IFS=$'\n' une_liste=( ${une_liste} )
echo "# on sort les éléments un à un"
for uneLigne in ${une_liste[@]}
do
echo "${uneLigne}"
done
version plus complète
#!/bin/bash
declare -a couleurs
# Toutes les commandes suivantes dans ce script traiteront
#+ la variable "couleurs" comme un tableau.
echo "rouge vert bleu noir blanc"
echo "Entrez vos couleurs favorites (séparées par un espace)."
read -a couleurs # Entrez au moins trois couleurs pour démontrer les
#+ fonctionnalités ci-dessous.
# Option spéciale pour la commande 'read'
#+ permettant d'affecter les éléments dans un tableau.
echo
nb_element=${#couleurs[@]}
# Syntaxe spéciale pour extraire le nombre d'éléments d'un tableau.
# nb_element=${#couleurs[*]} fonctionne aussi.
#
# La variable "@" permet de diviser les mots compris dans des guillemets
#+ (extrait les variables séparées par des espaces blancs).
#
# Ceci correspond au comportement de "$@" et "$*"
#+ dans les paramètres de positionnement.
index=0
while [ "$index" -lt "$nb_element" ]
do # Liste tous les éléments du tableau.
echo ${couleurs[$index]}
let "index = $index + 1"
# ou index+=1 avec Bash 3.1 et suivants
done
# Chaque élément du tableau est listé sur une ligne séparée.
# Si ceci n'est pas souhaité, utilisez echo -n "${couleurs[$index]} "
#
echo 'Pour le faire avec une boucle "for":'
for i in "${couleurs[@]}"
do
echo "$i"
done
echo
# Encore une fois, liste tous les éléments d'un tableau, mais en utilisant une
#+ méthode plus élégante.
echo ${couleurs[@]} # echo ${couleurs[*]} fonctionne aussi.
echo
# La commande "unset" supprime les éléments d'un tableau ou un tableau entier.
unset couleurs[1] # Supprime le deuxième élément d'un tableau.
# Même effet que couleurs[1]=
echo ${couleurs[@]} # Encore un tableau liste, dont le deuxième
# élément est manquant.
unset couleurs # Supprime le tableau entier.
# unset couleurs[*] et
#+ unset couleurs[@] fonctionnent aussi.
echo; echo -n "couleurs parties."
echo ${couleurs[@]} # Affiche le tableau une nouvelle fois, maintenant
#+ vide.
journaliser 1
_journal() {
nomlogiciel="${0##*/}"
fichier_log="$nomlogiciel.log"
> "$fichier_log"
}
echo "ouverture du journal"
_journal
journal (){
echo "$@" >> "$fichier_log"
}
journaliser 2
#durée d'exécution pour horodatage du log
START=$(date +%s.%N)
#ETAGE JOURNAL
_journal () {
nomlogiciel="${0##*/}"
fichier_log="$nomlogiciel.log"
#on vide le log ou on le crée si il n'existe pas
> "${fichier_log}"
journal "ouverture - $(date)"
journal "Ligne ${LINENO}--\t\t------------------------"
}
journal () {
local NOW=$(date +%s.%N)
local DIFF=$(echo "${NOW} - ${START}" | bc)
echo -e "[${DIFF}] ${@}" >> "${fichier_log}"
#echo -e "${@}" >> "${fichier_log}"
}
_journal
un splashscreen
splashScreen () {
(echo "<h1>PIL v$VERSION</h1><img src=\"data:"
mimetype -b "$1"
echo -n ";base64,"
base64 "$1"
echo "\">" ;) | zenity --text-info --timeout=2 --width=400 --height=500 --ok-label="Go" --cancel-label="" --html --filename=/dev/stdin
}
splashScreen "${chemin_Image}}" >/dev/null ;
gestion des fichier ini / conf
_iniFile () {
journal "appel de : ${FUNCNAME} ${@}"
if [ -f "${fichierIni}" ]; then
chargerIni ;
else
journal "création fichier ini"
touch "${fichierIni}" ;
sauverIni ;
fi
journal "sortie ${FUNCNAME} : $?"
}
chargerIni () {
journal "appel de : ${FUNCNAME} ${@}"
while read line ;
do
parserLigneIni "$line" ;
done < "${fichierIni}" ;
if [ ! -d "$chemin_Du_Prog" ] ;
then
localisation ;
journal "Erreur de chemin - fichier ini ré-initialisé" ;
sauverIni ;
fi
journal "sortie ${FUNCNAME} : $?"
}
sauverIni () {
journal "appel de : ${FUNCNAME} ${@}"
echo "chemin_du_prog=${chemin_du_prog}
fichier_tweaklist=${fichier_tweaklist}
fichier_log=${fichier_log}
fichier_ini=${fichier_ini}
fichier_aide=${fichier_aide}
chemin_de_data=${chemin_de_data}
chemin_des_images==${chemin_des_images=}
chemin_des_modules=${chemin_des_modules}
" | tee "${fichierIni}" >/dev/null ;
journal "sortie ${FUNCNAME} : $?"
}
parserLigneIni () {
journal "appel de : ${FUNCNAME} ${@}"
i=${@} ;
case $i in
#~xxxxx=*) xxxxxx="${i#*=}" ;;
chemin_du_prog=*) chemin_du_prog="${i#*=}" ;;
fichier_tweaklist=*) fichier_tweaklist="${i#*=}" ;;
fichier_log=*) fichier_log="${i#*=}" ;;
fichier_ini=*) fichier_ini="${i#*=}" ;;
fichier_aide=*) fichier_aide="${i#*=}" ;;
chemin_de_data=*) chemin_de_data="${i#*=}" ;;
chemin_des_images==*) chemin_des_images=="${i#*=}" ;;
chemin_des_modules=*) chemin_des_modules="${i#*=}" ;;
esac
}
_iniFile ;
Les Conditions
tester une ou plusieurs conditions
if [ $? -ne 0 ] ; then echo "OUI" ; else echo "NON" ; fi ;
ou plutôt
if [ $? -ne 0 ]
then
echo "OUI"
else
echo "NON"
fi
[ $? -eq 0 ] && echo "OUI" || echo "NON";
[[ $? -eq 0 ]] && echo "OUI" || echo "NON";
[Résolu] Différence entre "[ un test ]" et "[[ un test ]]" ???
réponses
ici et
ici sur le même fil
on a surtout besoin de tableaux qui reprennent les
types de test
et surtout
man test
😃 😉 :cool: (là si on ne le voit pas... Ah si
MAN TEST)
Les pipes
Les pipes permettent de router un flux vers une prochaine fonction
echo "Convertir espaces en underscore :"
echo $maVariable | tr " " "_"
echo "Passer tout en minuscules"
echo $maVariable | tr [:upper:] [:lower:]
echo "Retablir les esapces"
echo $maVariable | tr "_" " "
nb : ici le tr pour l'exemple, bash possède des fonctions pour les chaînes de caractères voir post
Watael a écritecho "Convertir espaces en underscore :"
echo "${maVariable// /_}"
echo "Passer tout en minuscules"
echo "${maVariable,,}"
echo "Retablir les esapces"
echo "${maVariable//_/ }"
Trim
on peut souhaiter appliquer des actions à la fin du script
TRIM permet d’intercepter des demandes
https://www.jujens.eu/posts/2015/Jan/09/utiliser-trap-bash/
# Par exemple :
# trap "echo yollo" 2 3
# affichera yollo quand on fait Ctrl-C.
#
# On obtient la liste des signaux avec leurs numéros et leurs noms avec la commande kill.
# kill -l
# 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL
# 5) SIGTRAP 6) SIGABRT 7) SIGEMT 8) SIGFPE
# 9)SIGKILL 10) SIGBUS 11) SIGSEGV 12) SIGSYS
#
# A priori, il est possible d'utiliser le nom du signal
# plutôt que le numéro avec trap
callTerm () {
echo "function callTerm"
exit 3
}
callUsr1 () {
echo "function callUsr1"
}
pid=$$
echo "pid = $pid
# une fois le script démarré,
# lancer un signal depuis un second terminal qui mettra fin à celui ci :
# SIGTERM version 1
# $ kill -TERM numero_pid
kill -TERM $pid
# SIGTERM version 2
# $ kill numero_pid
kill $pid
# SIGUSR1
# $ kill -USR1 numero_pid
kill -USR1 $pid
"
sleep 5
x-terminal-emulator &
clear
trap callTerm TERM # callTerm est une fonction à déclarer en début de scrit
trap callUsr1 USR1 # callUsr1 est également une fonction
echo "Lancer une des fonctions depuis le second terminal
kill -USR1 $pid
puis
kill $pid
ou
kill -TERM $pid
ou
Appuyer sur Entrée pour continuer..."
read r
pour des valeurs temporaires FIFO
PID=$$
FIFO=/tmp/FIFO${PID}
mkfifo ${FIFO}
trap "rm -f ${FIFO}" EXIT
être sudoer
certains scripts doivent être exécutés par un sudoer
2 façon de faire : soit le script quitte en réclamant un sudo, soit le script se relance lui même avec le sudo...
je met ici un exemple pour la seconde éventualité :
echo "ROOT OBLIGATOIRE"
if [ "$UID" -ne "0" ]
then
echo "Vous devez être en mode SU pour pouvoir utilisé ce sript"
sleep 1
echo "Entrer le mot de passe root, je relance la commande $NOM_LOGICIEL"
sudo ./"$NOM_LOGICIEL"
exit 1
fi
_main (){
zenity --info --text="ne peut se lancer qu'en sudoer"
}
_main
NB : if [ "$UID" -ne "0" ] est une façon de tester les droits de l'utilisateur
on peut aussi tester l'appartenance de l'utilisateur au groupe de sudo (en plus de l'autre test)
groups | grep sudo
donnera :
estSudoer=$(groups | grep sudo)
if [ "$estSudoer" > 1 ]
then
echo "$USER est sudoer"
else
echo "$USER n'est pas sudoer"
fi
Les infos glanées sur ce fil :
Watael a écritbash sait afficher les dates, et assigner des variables avec printf.
les noms de variables tout en majuscules sont réservés aux variables d'environnement, pas à celles des utilisateurs.
Sub0 a écrit
Pourquoi se priver de [[ … ]], qui n’a que des avantages ?
Le exit 0 à la fin des scripts est tout à fait inutile. Si le script arrive là, $? sera égal à 0 de toutes manières.
Toujours utiliser read avec l’option -r, sauf volonté explicitement contraire.
nam1962 a écritTiens, un petit lien avec quelques astuces utiles :
[lien ajouté au début du post]
En particulier
!! qui reprend une commande ou on a oublié le sudo :
~]$ X -version
/usr/lib/xorg-server/Xorg.wrap: Only console users are allowed to run the X server
[moi-meme@ordi2 ~]$ sudo !!
sudo X -version
[sudo] Mot de passe de moi-meme :
Et
at qui permet de fixer un délai, une heure ou une date d'exécution de la commande -->
http://www.thegeekstuff.com/2010/06/at-atq-atrm-batch-command-examples
J'aime aussi les astuces comme
ctrl - a pour revenir en début de ligne,
ctrl - e pour aller en fin de ligne,
ctrl - l pour effacer le contenu de la console...
Watael a écritman bash ne traite que de [[
parce
[ est un alias de
test.
je recommande également l'emploi de
test, plutôt que
[.
test a l'avantage de bien montrer qu'il est question d'une commande, et pas d'un groupement d'évaluations (j'ai souvent vu
[ être confondu avec des parenthèses; et avec des parenthèses, un test, « bah, forcément, ça va beaucoup moins bien marcher ! »).
k3c a écritici
#!/bin/sh
yell() { echo "$0: $*" >&2; }
die() { yell "$*"; exit 111; }
try() { "$@" || die "cannot $*"; }
utilisation :
# using it
try cd /some/place
try tar xzvfp /another/place/stuff.tbz
... je reviendrai ! :lol: