Bash: trucs et astuces : Différence entre versions

De TechWik
Aller à : navigation, rechercher
m (Grouper des cpommandes)
m
 
(17 révisions intermédiaires par le même utilisateur non affichées)
Ligne 1 : Ligne 1 :
== Fonctions utiles ==
+
= Fonctions utiles =
=== Conversions ===
+
==Conversions ==
   # conversion netmask => cidr
+
 
  # ex: mask2cidr 255.255.128.0 --> 17
+
=== conversions de base hexa, décimal, binaire, octal avec bc  ===
 +
Les variables speciales obase et ibase de bc définissent les bases de conversion des données d'entrée et sortie (par défaut base 10 pour les 2).
 +
 
 +
Par exemple, conversion décimale=>hexa:
 +
  $ echo "obase=16;12345"|bc
 +
  3039
 +
  $ echo "ibase=16;A039"|bc
 +
  41017
 +
 
 +
ou exemple dans un script:
 +
  $ for conv in 10101010:2:16 AA00:16:10 10101010:10:16; do \
 +
      IFS=: cc=($conv) \
 +
      out=$(echo "obase=${cc[2]};ibase=${cc[1]};${cc[0]}"|bc) \
 +
      echo "convert ${cc[0]} from base${cc[1]} -> base${cc[2]} => $out" \
 +
    done
 +
  ==> produit:
 +
   convert 10101010 from base2 -> base16 => AA
 +
  convert AA00 from base16 -> base10 => 43520
 +
  convert 10101010 from base10 -> base16 => 9A2112
 +
 
 +
Attention: pour la conversion hexa => decimal, il faut utiliser des majuscules (sinon resultat=0)!!
 +
 
 +
=== conversion netmask => cidr ===
 +
Exemple: mask2cidr 255.255.128.0 --> 17
 +
<syntaxhighlight lang="bash" line='line'>
 
   # suppose qu'il n'y a plus de "255." après un octet non-255
 
   # suppose qu'il n'y a plus de "255." après un octet non-255
 
   mask2cidr ()
 
   mask2cidr ()
Ligne 11 : Ligne 35 :
 
     echo $(( $2 + (${#x}/4) ))
 
     echo $(( $2 + (${#x}/4) ))
 
   }
 
   }
 
+
</syntaxhighlight>
  # conversion cidr => netmask  
+
=== conversion cidr => netmask ===
  # ex: cidr2mask 17 --> 255.255.128.0
+
Exemple: cidr2mask 17 --> 255.255.128.0
 +
<syntaxhighlight lang="bash" line='line'>
 
   cidr2mask ()
 
   cidr2mask ()
 
   {
 
   {
Ligne 20 : Ligne 45 :
 
     echo ${1-0}.${2-0}.${3-0}.${4-0}
 
     echo ${1-0}.${2-0}.${3-0}.${4-0}
 
   }
 
   }
 +
</syntaxhighlight>
 +
 +
=== expansion IPv6 ===
 +
Exemple: expand_ip6 fe80::68c8:c7b1:3199:f4b  --> fe80:0000:0000:0000:68c8:c7b1:3199:0f4b
 +
<syntaxhighlight lang="bash" line='line'>
 +
  expand_ip6() {
 +
    ip6=$1
 +
    IFS=: ff=($ip6); unset IFS
 +
    res=""
 +
    let ix=0
 +
    nf=${#ff[*]}
 +
    while [ $ix -lt $nf ]; do
 +
      it=${ff[ix]}
 +
      if [ ${#it} -gt 0 ]; then
 +
        let n=4-${#it};
 +
        while [ $n -gt 0 ]; do it="0${it}"; let n=n-1;done ;
 +
      else
 +
        let n=8-$nf;
 +
        it="0000";
 +
        while [ $n -gt 0 ]; do it="${it}:0000"; let n=n-1;done ;
 +
      fi;
 +
      if [ -z "$res" ];then
 +
        res=$it;
 +
      else
 +
        res="${res}:${it}";
 +
      fi
 +
      let ix=ix+1
 +
    done
 +
    echo $res
 +
  }
 +
</syntaxhighlight>
 +
 +
=== compression IPv6 ===
 +
Exemple: compress_ip6 fe80:0000:0000:0000:68c8:c7b1:3199:0f4b  --> fe80::68c8:c7b1:3199:f4b 
 +
<syntaxhighlight lang="bash" line='line'>
 +
  compress_ip6() {
 +
    echo $1 | sed -r -e 's/:(0+:){2,6}/::/' -e 's/:0+([1-9a-fA-F])/:\1/g'
 +
  }
 +
</syntaxhighlight>
  
=== manipuler des chaines de caractères ===
+
== manipuler des chaines de caractères ==
==== split chaine de caracteres: ====
+
=== split chaine de caracteres: ===
  1)IFS:
+
1)IFS:
 +
<syntaxhighlight lang="bash" line='line'>
 
     OIFS=$IFS
 
     OIFS=$IFS
 
     string="ABCDE-123456"
 
     string="ABCDE-123456"
Ligne 31 : Ligne 96 :
 
     echo $2 # >>> 123456
 
     echo $2 # >>> 123456
 
     IFS=$OIFS    # restituer le séparateur originel
 
     IFS=$OIFS    # restituer le séparateur originel
 +
</syntaxhighlight>
  
  2) récupérer le début ou la fin (ici separateur = ' ' )
+
2) récupérer le début ou la fin (ici separateur = ' ' )
 +
<syntaxhighlight lang="bash" line='line'>
 
     line="myhost 192.168.1.145 abcdefg 123456"
 
     line="myhost 192.168.1.145 abcdefg 123456"
  
 
     # enlever le dernier champ
 
     # enlever le dernier champ
     $ echo ${line% *}
+
     echo ${line% *}
     myhost 192.168.1.145 abcdefg
+
     # -> myhost 192.168.1.145 abcdefg
  
 
     # conserver le premier champ
 
     # conserver le premier champ
     $ echo ${line%% *}
+
     echo ${line%% *}
     myhost
+
     # -> myhost
  
 
     # enlever le premier champ
 
     # enlever le premier champ
     $ echo ${line#* }
+
     echo ${line#* }
     192.168.1.145 abcdefg 123456
+
     # -> 192.168.1.145 abcdefg 123456
  
 
     # conserver le dernier champ
 
     # conserver le dernier champ
     $ echo ${line##* }
+
     echo ${line##* }
     123456
+
     # -> 123456
 +
</syntaxhighlight>
  
  3) affecter les différents termes d'une ligne (cf IFS) à un tableau
+
3) affecter les différents termes d'une ligne (cf IFS) à un tableau
 +
<syntaxhighlight lang="bash" line='line'>
 
     line="myhost 192.168.1.145 is a good host"
 
     line="myhost 192.168.1.145 is a good host"
     $ termes=($line)
+
     termes=($line)
     $ echo ${termes[0]}
+
     echo ${termes[0]}
     myhost
+
     # -> myhost
     $ echo ${termes[4]}
+
     echo ${termes[4]}
     good
+
     # -> good
 +
</syntaxhighlight>
  
==== substring ====
+
=== substring ===
  
  Par exemple:
+
Utiliser ${variable:offset:length} Par exemple:
   $ date=2017-01-12
+
<syntaxhighlight lang="bash" line='line'>
   $ echo ${date:5:2}
+
   date=2017-01-12
 
+
   echo ${date:5:2}
   résultat: "01"
+
   # -> 01
 +
</syntaxhighlight>
  
=== récupérer le resultat d'une commande dans un tableau, ligne à ligne ===
+
=== substitution dans une chaîne ===
  
   1) IFS:
+
Utiliser ${main_string/search_term/replace_term}.
     $ IFS=$'\r\n'
+
Par exemple pour échapper le caractère $ dans une variable
    $ aa=($(grep blabla /pathtofile))
+
  myvar="${myvar/$/\\$}"
     $ echo ${aa[0]}
+
 
      ici ma premiere ligne.  
+
== Utiliser les expressions régulières directement dans le shell ==
 +
 
 +
Avec l'opérateur =~ , par exemple:
 +
<syntaxhighlight lang="bash" line='line'>
 +
  regex="([0-9]+)[[:space:]](.*)"
 +
  file="02 Rumour Has It.wma"
 +
  [[ $file =~ $regex ]] && echo "matched:(${BASH_REMATCH[1]}) -> ${BASH_REMATCH[2]}"
 +
</syntaxhighlight>
 +
donne:
 +
   matched:(02) -> Rumour Has It.wma
 +
 
 +
== récupérer le resultat d'une commande dans un tableau, ligne à ligne ==
 +
 
 +
1) IFS:
 +
<syntaxhighlight lang="bash" line='line'>
 +
     IFS=$'\r\n' aa=($(grep blabla /pathtofile))
 +
     unset IFS
 +
    echo ${aa[0]}
 +
    # -> ici ma premiere ligne.  
 +
</syntaxhighlight>
 
      
 
      
 
     manipuler le tableau:
 
     manipuler le tableau:
     for str in "${aa[@]}";do echo $str;done;
+
<syntaxhighlight lang="bash" line='line'>
 +
     for str in "${aa[@]}";do  
 +
      echo $str
 +
    done
 +
</syntaxhighlight>
  
  2) read: il faut passer par un fichier intermédiaire
+
2) read: il faut passer par un fichier intermédiaire
     $ grep blabla /pathtofile > /tmp/out
+
<syntaxhighlight lang="bash" line='line'>
     $ while read str; do echo $str;done < /tmp/out
+
     grep blabla /pathtofile > /tmp/out
 +
     while read str; do  
 +
      echo $str
 +
    done < /tmp/out
 +
</syntaxhighlight>
  
=== manipuler des variables ===
+
== manipuler des variables ==
  # variable avec valeur par defaut
+
* Valeur par defaut
 +
<syntaxhighlight lang="bash" line='line'>
 
     if [ ${var:=n} = "y" ]; then ...  
 
     if [ ${var:=n} = "y" ]; then ...  
     => affecte 'n' par défaut à $var.
+
     # => affecte 'n' par défaut à $var.
 +
</syntaxhighlight>
  
=== manipuler les lignes d'un fichier: exemple conversion d'un dossier mp3 => wav ===
+
== manipuler les lignes d'un fichier: exemple conversion d'un dossier mp3 => wav ==
 +
<syntaxhighlight lang="bash" line='line'>
 
   # chercher lister les fichiers mp3  
 
   # chercher lister les fichiers mp3  
 
   find . -name "*.mp3"  > /tmp/lst
 
   find . -name "*.mp3"  > /tmp/lst
Ligne 97 : Ligne 198 :
 
     let i=i+1;
 
     let i=i+1;
 
   done
 
   done
 +
</syntaxhighlight>
  
== Modifier quelques comportements avec shopt ==
+
== Autres built-in du shell ==
=== SSH et les alias ===
+
=== printf ===
 +
Syntaxe similaire à celle du C:
 +
 
 +
    # printf "%s is: %08x" hex 124
 +
    hex is: 0000007c
 +
 
 +
= Modifier quelques comportements avec shopt =
 +
== SSH et les alias ==
 
Les alias ne sont développés qu'avec les shells interactifs sauf si l'option expand_aliases du shell est activée par la commande shopt.  
 
Les alias ne sont développés qu'avec les shells interactifs sauf si l'option expand_aliases du shell est activée par la commande shopt.  
 
Pour utiliser des alias distants en SSH, ajouter dans .bashrc de l'utilisateur distant:  
 
Pour utiliser des alias distants en SSH, ajouter dans .bashrc de l'utilisateur distant:  
  
 +
<syntaxhighlight lang="bash" line='line'>
 
   if [ -z "$PS1" ]; then
 
   if [ -z "$PS1" ]; then
 
     shopt -s expand_aliases
 
     shopt -s expand_aliases
 
   fi
 
   fi
 +
</syntaxhighlight>
  
=== avec cdable_vars interpréter les variables pour la commande 'cd' ===
+
== avec cdable_vars interpréter les variables pour la commande 'cd' ==
 
Si  cette  option est active, un argument de la commande interne cd qui n'est pas un répertoire est supposé être un nom de variable dont la valeur est le répertoire visé. Exemple:
 
Si  cette  option est active, un argument de la commande interne cd qui n'est pas un répertoire est supposé être un nom de variable dont la valeur est le répertoire visé. Exemple:
  
Ligne 115 : Ligne 226 :
 
   /home/VMimages
 
   /home/VMimages
  
=== avec nocaseglob ignorer la casse pour développer les noms de fichiers ===
+
== avec nocaseglob ignorer la casse pour développer les noms de fichiers ==
 
Si cette option est active, bash traite les noms de fichiers sans différences minuscules/majuscules lors du développement des noms de fichiers
 
Si cette option est active, bash traite les noms de fichiers sans différences minuscules/majuscules lors du développement des noms de fichiers
  
Ligne 122 : Ligne 233 :
 
   CIS_Red_Hat_Enterprise_Linux_6_Benchmark_v1.4.0-oval.xml  CIS_Red_Hat_Enterprise_Linux_6_Benchmark_v1.4.0-xccdf.xml
 
   CIS_Red_Hat_Enterprise_Linux_6_Benchmark_v1.4.0-oval.xml  CIS_Red_Hat_Enterprise_Linux_6_Benchmark_v1.4.0-xccdf.xml
  
== Comportement / syntaxe bash ==  
+
= Comportement / syntaxe bash =
=== Grouper des commandes ===
+
== Grouper des commandes ==
 
* avec () les commandes placées dans la liste entre parenthèses sont exécutées dans un sous-shell. Il n'y a pas persistence dans le shell courant des variables manipulées dans ces commandes.
 
* avec () les commandes placées dans la liste entre parenthèses sont exécutées dans un sous-shell. Il n'y a pas persistence dans le shell courant des variables manipulées dans ces commandes.
  
Ligne 129 : Ligne 240 :
  
 
   { var=$(<"$file"); } 2>/dev/null;
 
   { var=$(<"$file"); } 2>/dev/null;
 +
 +
= Manipuler l'historique  =
 +
* Répéter la dernière commande : !!
 +
* Répéter la dernière commande commançant par un motif:
 +
    $ !echo
 +
    echo Bash Shortcuts
 +
    Bash Shortcuts
 +
et avec ":p" afficher la dernière commande commançant par un motif sans l'exécuter (mais l'exécuter ensuite avec !!):
 +
    $ echo Bash Shortcuts
 +
    Bash Shortcuts
 +
    $ wc -m /etc/bash_completion
 +
    45 /etc/bash_completion
 +
    $ !echo:p
 +
    echo Bash Shortcuts
 +
    $ !!
 +
    echo Bash Shortcuts
 +
    Bash Shortcuts
 +
* Rappeler les arguments de la dernière commande (tous : !* , le premier: !^ , le dernier: !$ ).
 +
    $ echo First Bash Shortcuts arg is not last
 +
    First Bash Shortcuts arg is not last
 +
    $ touch !*
 +
    touch First Bash Shortcuts arg is not last
 +
    $ ls
 +
    First Bash Shortcuts arg is not last ...
 +
    $ rm First Bash Shortcuts arg is not last
 +
    $ echo !^
 +
    First
 +
    $ echo First Bash Shortcuts arg is not last
 +
    $ touch !*
 +
    touch last
 +
* Rappeler la dernière commande avec substitution d'une partie
 +
    $ echo this is our args
 +
    this is our args
 +
    $ ^our args^my last word^
 +
    echo this is my last word
 +
    this is my last word
 +
* Rappeler une commande  avec substitution
 +
    $ localectl list-keymaps |grep "^fr"
 +
    ...
 +
    $ ls
 +
    ...
 +
    $ !locale:s/fr/us/
 +
    localectl list-keymaps |grep "^us"
 +
    us
 +
    us-acentos
 +
    ...
 +
* Rappeler des commandes avec leur position dans l'historique
 +
    $ history
 +
    1018  find /usr/share/doc/ -name bonding.txt
 +
    1019  echo this is my last word
 +
    1020  localectl list-keymaps |grep "^us"
 +
    1021  history
 +
    $ !-3
 +
    echo this is my last word
 +
    this is my last word
 +
    $ !1018
 +
    find /usr/share/doc/ -name bonding.txt
 +
    /usr/share/doc/kernel-doc-3.10.0/Documentation/networking/bonding.txt
 +
 +
= Vérfication de qualité du code shell =
 +
https://www.shellcheck.net/
  
 
[[Category:Bash]]
 
[[Category:Bash]]
 
[[Category:Tips&Tricks]]
 
[[Category:Tips&Tricks]]

Version actuelle datée du 1 février 2022 à 14:02

Fonctions utiles

Conversions

conversions de base hexa, décimal, binaire, octal avec bc

Les variables speciales obase et ibase de bc définissent les bases de conversion des données d'entrée et sortie (par défaut base 10 pour les 2).

Par exemple, conversion décimale=>hexa:

 $ echo "obase=16;12345"|bc 
 3039
 $ echo "ibase=16;A039"|bc 
 41017

ou exemple dans un script:

 $ for conv in 10101010:2:16 AA00:16:10 10101010:10:16; do \
     IFS=: cc=($conv) \
     out=$(echo "obase=${cc[2]};ibase=${cc[1]};${cc[0]}"|bc) \
     echo "convert ${cc[0]} from base${cc[1]} -> base${cc[2]} => $out" \
   done
 ==> produit:
 convert 10101010 from base2 -> base16 => AA
 convert AA00 from base16 -> base10 => 43520
 convert 10101010 from base10 -> base16 => 9A2112

Attention: pour la conversion hexa => decimal, il faut utiliser des majuscules (sinon resultat=0)!!

conversion netmask => cidr

Exemple: mask2cidr 255.255.128.0 --> 17

1   # suppose qu'il n'y a plus de "255." après un octet non-255
2   mask2cidr ()
3   {
4     local x=${1##*255.}
5     set -- 0^^^128^192^224^240^248^252^254^ $(( (${#1} - ${#x})*2 )) ${x%%.*}
6     x=${1%%$3*}
7     echo $(( $2 + (${#x}/4) ))
8   }

conversion cidr => netmask

Exemple: cidr2mask 17 --> 255.255.128.0

1   cidr2mask ()
2   {
3     set -- $(( 5 - ($1 / 8) )) 255 255 255 255 $(( (255 << (8 - ($1 % 8))) & 255 )) 0 0 0
4     [ $1 -gt 1 ] && shift $1 || shift
5     echo ${1-0}.${2-0}.${3-0}.${4-0}
6   }

expansion IPv6

Exemple: expand_ip6 fe80::68c8:c7b1:3199:f4b --> fe80:0000:0000:0000:68c8:c7b1:3199:0f4b

 1   expand_ip6() {
 2     ip6=$1
 3     IFS=: ff=($ip6); unset IFS
 4     res=""
 5     let ix=0
 6     nf=${#ff[*]}
 7     while [ $ix -lt $nf ]; do 
 8       it=${ff[ix]}
 9       if [ ${#it} -gt 0 ]; then 
10         let n=4-${#it}; 
11         while [ $n -gt 0 ]; do it="0${it}"; let n=n-1;done ; 
12       else 
13         let n=8-$nf; 
14         it="0000"; 
15         while [ $n -gt 0 ]; do it="${it}:0000"; let n=n-1;done ; 
16       fi; 
17       if [ -z "$res" ];then 
18         res=$it; 
19       else 
20         res="${res}:${it}";
21       fi
22       let ix=ix+1 
23     done
24     echo $res
25   }

compression IPv6

Exemple: compress_ip6 fe80:0000:0000:0000:68c8:c7b1:3199:0f4b --> fe80::68c8:c7b1:3199:f4b

1   compress_ip6() {
2     echo $1 | sed -r -e 's/:(0+:){2,6}/::/' -e 's/:0+([1-9a-fA-F])/:\1/g'
3   }

manipuler des chaines de caractères

split chaine de caracteres:

1)IFS:

1     OIFS=$IFS
2     string="ABCDE-123456"
3     IFS=- # use "local IFS=-" inside the function
4     set $string
5     echo $1 # >>> ABCDE
6     echo $2 # >>> 123456
7     IFS=$OIFS     # restituer le séparateur originel

2) récupérer le début ou la fin (ici separateur = ' ' )

 1     line="myhost 192.168.1.145 abcdefg 123456"
 2 
 3     # enlever le dernier champ
 4     echo ${line% *}
 5     # -> myhost 192.168.1.145 abcdefg
 6 
 7     # conserver le premier champ
 8     echo ${line%% *}
 9     # -> myhost
10 
11     # enlever le premier champ
12     echo ${line#* }
13     # -> 192.168.1.145 abcdefg 123456
14 
15     # conserver le dernier champ
16     echo ${line##* }
17     # -> 123456

3) affecter les différents termes d'une ligne (cf IFS) à un tableau

1     line="myhost 192.168.1.145 is a good host"
2     termes=($line)
3     echo ${termes[0]}
4     # -> myhost
5     echo ${termes[4]}
6     # -> good

substring

Utiliser ${variable:offset:length} Par exemple:

1    date=2017-01-12
2    echo ${date:5:2}
3   # -> 01

substitution dans une chaîne

Utiliser ${main_string/search_term/replace_term}. Par exemple pour échapper le caractère $ dans une variable

  myvar="${myvar/$/\\$}"

Utiliser les expressions régulières directement dans le shell

Avec l'opérateur =~ , par exemple:

1   regex="([0-9]+)[[:space:]](.*)"
2   file="02 Rumour Has It.wma"
3   [[ $file =~ $regex ]] && echo "matched:(${BASH_REMATCH[1]}) -> ${BASH_REMATCH[2]}"

donne:

 matched:(02) -> Rumour Has It.wma

récupérer le resultat d'une commande dans un tableau, ligne à ligne

1) IFS:

1     IFS=$'\r\n' aa=($(grep blabla /pathtofile))
2     unset IFS
3     echo ${aa[0]}
4     # -> ici ma premiere ligne.
   manipuler le tableau:
1     for str in "${aa[@]}";do 
2       echo $str
3     done

2) read: il faut passer par un fichier intermédiaire

1     grep blabla /pathtofile > /tmp/out
2     while read str; do 
3       echo $str
4     done < /tmp/out

manipuler des variables

  • Valeur par defaut
1     if [ ${var:=n} = "y" ]; then ... 
2     # => affecte 'n' par défaut à $var.

manipuler les lignes d'un fichier: exemple conversion d'un dossier mp3 => wav

1   # chercher lister les fichiers mp3 
2   find . -name "*.mp3"  > /tmp/lst
3   # lire la liste dans un tableau (1 enregistrement par ligne)
4   IFS=$'\n' read -d '' -r -a files < /tmp/lst
5   while [ $i -lt ${#files[@]} ]; do
6     fout=` echo ${files[$i]} | sed "s/.mp3/.wav/"`; 
7     lame --decode "${files[$i]}" "../wav/$fout";
8     let i=i+1;
9   done

Autres built-in du shell

printf

Syntaxe similaire à celle du C:

   # printf "%s is: %08x" hex 124
   hex is: 0000007c

Modifier quelques comportements avec shopt

SSH et les alias

Les alias ne sont développés qu'avec les shells interactifs sauf si l'option expand_aliases du shell est activée par la commande shopt. Pour utiliser des alias distants en SSH, ajouter dans .bashrc de l'utilisateur distant:

1   if [ -z "$PS1" ]; then
2     shopt -s expand_aliases
3   fi

avec cdable_vars interpréter les variables pour la commande 'cd'

Si cette option est active, un argument de la commande interne cd qui n'est pas un répertoire est supposé être un nom de variable dont la valeur est le répertoire visé. Exemple:

 $ shopt -s cdable_vars  
 $ vms=/home/VMimages
 $ cd vms
 /home/VMimages

avec nocaseglob ignorer la casse pour développer les noms de fichiers

Si cette option est active, bash traite les noms de fichiers sans différences minuscules/majuscules lors du développement des noms de fichiers

 $ shopt -s nocaseglob  
 $ ls cis*
 CIS_Red_Hat_Enterprise_Linux_6_Benchmark_v1.4.0-oval.xml  CIS_Red_Hat_Enterprise_Linux_6_Benchmark_v1.4.0-xccdf.xml

Comportement / syntaxe bash

Grouper des commandes

  • avec () les commandes placées dans la liste entre parenthèses sont exécutées dans un sous-shell. Il n'y a pas persistence dans le shell courant des variables manipulées dans ces commandes.
  • avec {} les commandes placées entre accolades sont exécutées dans le contexte de shell courant. Le point virgule séparant les commandes est obligatoire sur la dernière, ainsi que les espaces autour de début et fin de bloc. D'éventuelles redirections peuvent être appliquées au bloc de commandes. Par exemple, lire un fichier dans une variable, et éviter les messages d'erreur:
 { var=$(<"$file"); } 2>/dev/null;

Manipuler l'historique

  • Répéter la dernière commande : !!
  • Répéter la dernière commande commançant par un motif:
   $ !echo
   echo Bash Shortcuts
   Bash Shortcuts

et avec ":p" afficher la dernière commande commançant par un motif sans l'exécuter (mais l'exécuter ensuite avec !!):

   $ echo Bash Shortcuts
   Bash Shortcuts
   $ wc -m /etc/bash_completion
   45 /etc/bash_completion
   $ !echo:p
   echo Bash Shortcuts
   $ !!
   echo Bash Shortcuts
   Bash Shortcuts
  • Rappeler les arguments de la dernière commande (tous : !* , le premier: !^ , le dernier: !$ ).
   $ echo First Bash Shortcuts arg is not last
   First Bash Shortcuts arg is not last
   $ touch !*
   touch First Bash Shortcuts arg is not last
   $ ls
   First Bash Shortcuts arg is not last ... 
   $ rm First Bash Shortcuts arg is not last
   $ echo !^
   First
   $ echo First Bash Shortcuts arg is not last
   $ touch !*
   touch last
  • Rappeler la dernière commande avec substitution d'une partie
   $ echo this is our args
   this is our args
   $ ^our args^my last word^
   echo this is my last word 
   this is my last word
  • Rappeler une commande avec substitution
   $ localectl list-keymaps |grep "^fr"
   ...
   $ ls
   ... 
   $ !locale:s/fr/us/
   localectl list-keymaps |grep "^us"
   us
   us-acentos
   ... 
  • Rappeler des commandes avec leur position dans l'historique
   $ history
   1018  find /usr/share/doc/ -name bonding.txt
   1019  echo this is my last word 
   1020  localectl list-keymaps |grep "^us"
   1021  history
   $ !-3
   echo this is my last word 
   this is my last word
   $ !1018
   find /usr/share/doc/ -name bonding.txt
   /usr/share/doc/kernel-doc-3.10.0/Documentation/networking/bonding.txt

Vérfication de qualité du code shell

https://www.shellcheck.net/