User Tools

Site Tools


informatique:linux:bash

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
informatique:linux:bash [2020/11/12 15:00] – [Rappels et substitutions] pteuinformatique:linux:bash [2023/01/09 10:52] (current) – [-e] pteu
Line 3: Line 3:
 {{:informatique:linux:bash_logo.png?nolink&200 |}} {{:informatique:linux:bash_logo.png?nolink&200 |}}
  
-**Bash** est un interpréteur de commande, un "shell". Il possède beaucoup de caractéristiques et fonctions communes avec ''sh'' ou ''zsh''.+**Bash** est un interpréteur de commande, un "shell". Il possède beaucoup de caractéristiques et fonctions communes avec ''sh'', ''ksh'', ''zsh'' ou plus largement ''*sh''.
  
-Pour la partie programmation et les variables, voir la page [[informatique:linux:programmation_shell|Programmation Shell]].+Cette page se concentrera sur la prise en main de **bash**, sa configuration, ses raccourcis clavier, les enchaînements de commandes et quelques tips ; pour la partie programmation/scripting et variables, voir la page [[informatique:linux:programmation_shell|Programmation Shell]].
  
  
Line 52: Line 52:
   * ''^foo^bar'' relancer la dernière commande en remplaçant la première occurrence de "foo" par "bar". Pour supprimer "foo" : ''^foo'' tout court.   * ''^foo^bar'' relancer la dernière commande en remplaçant la première occurrence de "foo" par "bar". Pour supprimer "foo" : ''^foo'' tout court.
   * ''!!:gs/foo/bar'' relance la dernière commande en remplaçant toutes les occurrences de "foo" par "bar".   * ''!!:gs/foo/bar'' relance la dernière commande en remplaçant toutes les occurrences de "foo" par "bar".
 +
 =====Syntaxe===== =====Syntaxe=====
  
Line 59: Line 60:
   * ''<cmd1>&&<cmd2>'' permet de lancer //<cmd1>//, puis //<cmd2>// uniquement si //<cmd1>// renvoie //true// (se termine correctement)   * ''<cmd1>&&<cmd2>'' permet de lancer //<cmd1>//, puis //<cmd2>// uniquement si //<cmd1>// renvoie //true// (se termine correctement)
   * ''<cmd1>||<cmd2>'' lancer //<cmd1>//, puis //<cmd2>// uniquement si //<cmd1>// renvoie //false//   * ''<cmd1>||<cmd2>'' lancer //<cmd1>//, puis //<cmd2>// uniquement si //<cmd1>// renvoie //false//
-  * ''<cmd1>|<cmd2>'' redirige la sortie standart de //<cmd1>// vers l'entrée standard de //<cmd2>//+  * ''<cmd1>|<cmd2>'' redirige la sortie standard de //<cmd1>// vers l'entrée standard de //<cmd2>//
   * ''<cmd1>|xargs <cmd2>'' convertit la sortie de //<cmd1>// en paramètres de //<cmd2>//   * ''<cmd1>|xargs <cmd2>'' convertit la sortie de //<cmd1>// en paramètres de //<cmd2>//
   * ''<cmd> > <fic>'' redirige la sortie (STDOUT) de //<cmd>// vers le fichier //<fic>// (le fichier est vidé (>))   * ''<cmd> > <fic>'' redirige la sortie (STDOUT) de //<cmd>// vers le fichier //<fic>// (le fichier est vidé (>))
-  * ''<cmd> >> <fic>'' redirige la sortie de //<cmd>// à la fin du fichier //<fic>// (>>)  +  * ''<cmd> <nowiki>>></nowiki> <fic>'' redirige la sortie de //<cmd>// à la fin du fichier //<fic>// (<nowiki>>></nowiki>)  
-  * ''<cmd> 2><fic>'' redirige la sortie d'erreur (STDERR) vers //<fic>// +  * ''<cmd> 2> <fic>'' redirige la sortie d'erreur (STDERR) vers //<fic>// 
-On trouvera par exemple ''<cmd> >/dev/null 2>/dev/null'' pour que //<cmd>// n'affiche rien à l'écran (ni la sortie standart ni la sortie d'erreur).  +On trouvera par exemple ''<cmd> >/dev/null 2>/dev/null'' pour que //<cmd>// n'affiche rien à l'écran (ni la sortie standard ni la sortie d'erreur).  
-  * ''<cmd> 2>&1'' redirige la sortie d'erreur vers la sortie standart (**&1**) +  * ''<cmd> 2> &1'' redirige la sortie d'erreur vers la sortie standard (**&1**) 
-  * ''<cmd> < <fic>'' redirige le contenu de //<fic>// sur l'entrée standart de //<cmd>// +  * ''<cmd> < <fic>'' redirige le contenu de //<fic>// sur l'entrée standard de //<cmd>// 
-  * Les doubles quotes ''"'' n'interprètent que les caractères spéciaux **$**, **\** et **'** (quote) +  * Les apostrophes (quotes) permettant de définir une chaîne de caractère contenant des espaces : 
-  Les simples quotes ''''' n'interprètent aucun caractère spécial+    * les doubles quotes ''"'' interprètent les caractères spéciaux **$**, **\** et **'** (quote) 
 +    les simples quotes ''''' n'interprètent aucun caractère spécial
   * Les caractères spéciaux sont : ''& ~ ; \ " ' ` # ( ) [ ] | $ * ! ? < >''   * Les caractères spéciaux sont : ''& ~ ; \ " ' ` # ( ) [ ] | $ * ! ? < >''
  
Line 85: Line 87:
 Les options de bash peuvent se modifier au lancement sous forme de paramètre (''bash -e'' par ex.) ou dans un script via le mot-clé ''set''. Elles permettent de tuner le shell en modifiant son comportement par défaut. Les options de bash peuvent se modifier au lancement sous forme de paramètre (''bash -e'' par ex.) ou dans un script via le mot-clé ''set''. Elles permettent de tuner le shell en modifiant son comportement par défaut.
  
 +====-e====
  
-=====Debugger un script=====+Avec l'option ''-e'', bash se termine dès qu'une commande se termine avec un code de retour en erreur (différent de 0). Impossible a activer dans un shell, mais pratique pour éviter que des erreurs non prévues dans un script ne provoquent de gros problèmes. 
 + 
 +Cependant cela ne marche pas correctement avec certaines commandes comme grep, qui retourne 1 s'il ne matche pas (ce qui n'est certainement pas une erreur qui vaut le coup que l'on arrête le script). Alors, comme indiqué dans [[https://stackoverflow.com/questions/9952177/whats-the-meaning-of-the-parameter-e-for-bash-shell-command-line/9952249|ce thread de stackoverflow]] : 
 +    * soit on gère l'erreur avec un ''grep TRUC machin.txt || :'' : on gère le retour pour que bash ne la "voit" pas (si aucune action n'est nécessaire : ''grep TRUC machin.txt || true'' suffit ; cependant ce n'est pas idéal, car on masque tous les codes d'erreur (pas que 1). 
 +    * soit, plus compliqué mais plus pertinent, on créé une fonction "grep" dans notre script pour surcharger la commande système grep, qui va filtrer les codes de retour 1 (motif non trouvé) mais pas les autres, que bash pourra interpréter (erreur=2 : fichier inexistant par exemple). 
 +<code bash> 
 +#!/bin/bash -e 
 +function grep () { 
 +    local exit_code 
 +    command grep "$@" || exit_code=$? 
 +    return $(( exit_code == 1 ? 0 : exit_code )) 
 +
 +grep PATTERN FILE     # won't kill script if no matches are found 
 +</code> 
 +Rappel : ''command'' permet de lancer la commande qui suit ("grep" ici) parmi les commandes internes et le contenu du $PATH uniquement, afin que notre fonction ne devienne pas récursive !
  
-Pour vérifier la syntaxe d'un script sans lancer : ''set -n'' (ou ''bash -n mon_script.sh'')+====-x====
  
 Pour le débugger un script, ajouter dans le script : Pour le débugger un script, ajouter dans le script :
Line 99: Line 116:
 #!/bin/sh -v #!/bin/sh -v
 </code> </code>
 +
 +====-n====
 +
 +Pour vérifier la syntaxe d'un script sans le lancer (//run-dry//) : ''set -n'' (ou ''bash -n mon_script.sh'')
 +
 +====-o pipefail====
 +
 +Par défaut, après une suite de pipe (''|'') bash ne retient que le code de retour de la dernière commande (la plus à droite). En activant l'option pipefail, bash va renvoyer le dernier code de retour __en erreur__ dans la suite de pipes, ou "0" si toutes les commandes se terminent correctement.
 +
 +Combiné avec ''-e'', permet de terminer le script courant en cas de code d'erreur non traitée, même celles "cachées" par un pipe.
 +
 +Par exemple:
 +<code bash>
 +#!/bin/bash
 +#set -eo pipefail
 +foo | echo test1
 +echo test2
 +#test1
 +#line 3: foo: command not found
 +#test2
 +</code>
 +
 +<code bash>
 +#!/bin/bash
 +set -eo pipefail
 +foo | echo test1
 +echo test2
 +#test1
 +#line 3: foo: command not found
 +</code>
 +
 +====-u====
 +
 +Avec cette option, bash va générer une erreur et stopper son exécution si une variable non déclarée est utilisée. Pour éviter cela, on utilisera la notation ''${var-default}'' pour s'assurer que si $var n'est pas définie, on lui attribuera la valeur "default" et bash ne génèrera pas d'erreur.
  
 =====.bashrc===== =====.bashrc=====
Line 340: Line 391:
 C=# C=#
 printf "%0.s${C}" $(seq 1 ${N}) printf "%0.s${C}" $(seq 1 ${N})
 +</code>
 +
 +====Désactiver l'alias====
 +
 +Pour afficher si une commande est un alias, on peut faire : ''alias <cmd>'', par exemple :
 +<code bash>
 +alias ls
 + alias ls='ls --color=auto'
 +</code>
 +
 +Et si on souhaite la lancer sans l'alias (''ls'' tout court), on peut utiliser la syntaxe '''<cmd><nowiki>'</nowiki>'' ou ''\<cmd>'' :
 +<code bash>
 +'ls'
 +# ou
 +\ls
 +</code>
 +=====Liens/Ressources=====
 +
 +  * [[https://github.com/jlevy/the-art-of-command-line|The Art of Command Line]] (jlevy's GitHub)
 +  * [[https://betterdev.blog/minimal-safe-bash-script-template/|Minimal safe Bash script template]] (betterdev.blog)
 +Je pose ledit template ici, mais le lien ci-dessous vaut le détour car il explique chaque best-practice en détail !
 +<code bash>
 +#!/usr/bin/env bash
 +
 +set -Eeuo pipefail
 +trap cleanup SIGINT SIGTERM ERR EXIT
 +
 +script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd -P)
 +
 +usage() {
 +  cat << EOF # remove the space between << and EOF, this is due to web plugin issue
 +Usage: $(basename "${BASH_SOURCE[0]}") [-h] [-v] [-f] -p param_value arg1 [arg2...]
 +
 +Script description here.
 +
 +Available options:
 +
 +-h, --help      Print this help and exit
 +-v, --verbose   Print script debug info
 +-f, --flag      Some flag description
 +-p, --param     Some param description
 +EOF
 +  exit
 +}
 +
 +cleanup() {
 +  trap - SIGINT SIGTERM ERR EXIT
 +  # script cleanup here
 +}
 +
 +setup_colors() {
 +  if [[ -t 2 ]] && [[ -z "${NO_COLOR-}" ]] && [[ "${TERM-}" != "dumb" ]]; then
 +    NOFORMAT='\033[0m' RED='\033[0;31m' GREEN='\033[0;32m' ORANGE='\033[0;33m' BLUE='\033[0;34m' PURPLE='\033[0;35m' CYAN='\033[0;36m' YELLOW='\033[1;33m'
 +  else
 +    NOFORMAT='' RED='' GREEN='' ORANGE='' BLUE='' PURPLE='' CYAN='' YELLOW=''
 +  fi
 +}
 +
 +msg() {
 +  echo >&2 -e "${1-}"
 +}
 +
 +die() {
 +  local msg=$1
 +  local code=${2-1} # default exit status 1
 +  msg "$msg"
 +  exit "$code"
 +}
 +
 +parse_params() {
 +  # default values of variables set from params
 +  flag=0
 +  param=''
 +
 +  while :; do
 +    case "${1-}" in
 +    -h | --help) usage ;;
 +    -v | --verbose) set -x ;;
 +    --no-color) NO_COLOR=1 ;;
 +    -f | --flag) flag=1 ;; # example flag
 +    -p | --param) # example named parameter
 +      param="${2-}"
 +      shift
 +      ;;
 +    -?*) die "Unknown option: $1" ;;
 +    *) break ;;
 +    esac
 +    shift
 +  done
 +
 +  args=("$@")
 +
 +  # check required params and arguments
 +  [[ -z "${param-}" ]] && die "Missing required parameter: param"
 +  [[ ${#args[@]} -eq 0 ]] && die "Missing script arguments"
 +
 +  return 0
 +}
 +
 +parse_params "$@"
 +setup_colors
 +
 +# script logic here
 +
 +msg "${RED}Read parameters:${NOFORMAT}"
 +msg "- flag: ${flag}"
 +msg "- param: ${param}"
 +msg "- arguments: ${args[*]-}"
 </code> </code>
informatique/linux/bash.1605193204.txt.gz · Last modified: 2020/11/12 15:00 by pteu