Différences
Ci-dessous, les différences entre deux révisions de la page.
Les deux révisions précédentesRévision précédenteProchaine révision | Révision précédente | ||
informatique:outils:bash [2024/06/28 16:50] – [Fonctions utiles] bn8 | informatique:outils:bash [2025/08/21 12:47] (Version actuelle) – [Barre de progression] bn8 | ||
---|---|---|---|
Ligne 1: | Ligne 1: | ||
====== Bash ====== | ====== Bash ====== | ||
+ | |||
+ | ===== Substitution dans les variables ===== | ||
+ | |||
+ | * Chercher/ | ||
+ | * Pour chercher explicitement **au début** du contenu de la variable : '' | ||
+ | * Pour chercher explicitement **à la fin** du contenu de la variable : '' | ||
+ | * Pour remplacer **toutes les occurences** : '' | ||
+ | * Mise en **majuscule** (upper case) : '' | ||
+ | * Pour mettre **tout en majuscule** : '' | ||
+ | * Mise en **minuscule** (lower case) : '' | ||
+ | * Pour mettre **tout en minuscule** : '' | ||
===== Array ===== | ===== Array ===== | ||
Ligne 11: | Ligne 22: | ||
* lister toutes les clés d'un tableau associatif : '' | * lister toutes les clés d'un tableau associatif : '' | ||
* récupérer le nombre d' | * récupérer le nombre d' | ||
+ | * construire un tableau à partir d'une chaîne de caractères : Cela dépend du séparateur utilisé : | ||
+ | * avec un retour à la ligne : '' | ||
+ | * avec un espace (ou autre caractère unique et " | ||
+ | * ajouter des valeurs à un tableau existant : '' | ||
+ | * ajouter depuis un fichier : '' | ||
+ | * ajouter depuis la sortie d'une commande : '' | ||
+ | * Note : voir la fonction '' | ||
==== Fonctions utiles ==== | ==== Fonctions utiles ==== | ||
- | |||
=== in_array === | === in_array === | ||
Ligne 55: | Ligne 72: | ||
<code bash> | <code bash> | ||
function array_filter() { | function array_filter() { | ||
- | | + | |
- | local x=0 | + | for v in " |
- | for v in " | + | if [[ " |
- | if [ " | + | x=1 |
- | x=1 | + | elif [[ $x -eq 0 ]]; then |
- | elif [ $x -eq 0 ]; then | + | |
- | | + | |
- | | + | |
- | | + | fi |
- | fi | + | done |
- | done | + | printf |
- | printf %s "${VALUES}" | + | |
} | } | ||
</ | </ | ||
Ligne 74: | Ligne 90: | ||
a=(a b c d e) | a=(a b c d e) | ||
array_filter ${a[@]} -- c e | array_filter ${a[@]} -- c e | ||
- | # Output: a b d | + | # Output: |
+ | # a | ||
+ | # b | ||
+ | # d | ||
</ | </ | ||
Ligne 82: | Ligne 101: | ||
function array_intersect() { | function array_intersect() { | ||
local result_var=$1 | local result_var=$1 | ||
- | declare -g " | + | declare -ga " |
shift | shift | ||
local array1=() | local array1=() | ||
Ligne 101: | Ligne 120: | ||
for j in " | for j in " | ||
if [[ $i == $j ]]; then | if [[ $i == $j ]]; then | ||
- | declare -g " | + | declare -ga " |
break | break | ||
fi | fi | ||
Ligne 113: | Ligne 132: | ||
a=(a b c d e) | a=(a b c d e) | ||
b=(c d) | b=(c d) | ||
- | array_filter | + | array_intersect |
- | echo ${c[@]} | + | echo "${c[@]}" |
# Result: | # Result: | ||
c d | c d | ||
Ligne 140: | Ligne 159: | ||
# - 2 | # - 2 | ||
# - 3 | # - 3 | ||
+ | </ | ||
+ | |||
+ | === explode === | ||
+ | |||
+ | <code bash> | ||
+ | function explode() { | ||
+ | local output_var=$1 seperator=$2 | ||
+ | declare -ga " | ||
+ | mapfile -t " | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | **Utilisation :** | ||
+ | <code bash> | ||
+ | explode myarray " " "1 2 3" "4 5" | ||
+ | declare -p myarray | ||
+ | # Output: | ||
+ | # declare -a myarray=([0]=" | ||
+ | |||
+ | explode myarray " | ||
+ | 1 | ||
+ | 2 | ||
+ | 3" | ||
+ | declare -p myarray | ||
+ | # Output: | ||
+ | # declare -a myarray=([0]=" | ||
+ | </ | ||
+ | |||
+ | === check_regex === | ||
+ | |||
+ | <code bash> | ||
+ | function check_regex() { | ||
+ | [[ $(grep -Ec " | ||
+ | return 1 | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | === check_int === | ||
+ | |||
+ | **Pré-requis :** [[# | ||
+ | |||
+ | <code bash> | ||
+ | function check_int() { | ||
+ | check_regex " | ||
+ | [[ -n " | ||
+ | [[ -n " | ||
+ | return 0 | ||
+ | } | ||
</ | </ | ||
Ligne 146: | Ligne 213: | ||
<code bash> | <code bash> | ||
function format_duration { | function format_duration { | ||
- | | + | |
- | local D=$((T/ | + | local d=$((t/ |
- | local H=$((T/ | + | local h=$((t/ |
- | local M=$((T/60%60)) | + | local m=$((t/60%60)) |
- | local S=$((T%60)) | + | local s=$((t%60)) |
- | | + | |
- | printf ' | + | printf ' |
+ | } | ||
+ | </ | ||
+ | |||
+ | === format_size === | ||
+ | |||
+ | **Pré-requis :** [[# | ||
+ | |||
+ | <code bash> | ||
+ | declare -ra _FORMAT_SIZE_UNITS=( tb gb mb kb b ) | ||
+ | declare -rA _FORMAT_SIZE_UNITS_FACTOR=( | ||
+ | [" | ||
+ | function format_size() { | ||
+ | local size="" | ||
+ | for opt in " | ||
+ | opt=" | ||
+ | if [[ ${#opt} -gt 2 ]] && \ | ||
+ | [[ " | ||
+ | unit=${opt: | ||
+ | elif [[ ${#opt} -gt 1 ]] && \ | ||
+ | [[ " | ||
+ | unit=${opt: | ||
+ | elif [[ " | ||
+ | allow_zero=1 | ||
+ | elif [[ -z " | ||
+ | size=$opt | ||
+ | [[ " | ||
+ | check_int " | ||
+ | else | ||
+ | echo -n " | ||
+ | return 1 | ||
+ | fi | ||
+ | done | ||
+ | if [[ $size -eq 0 ]]; then | ||
+ | [[ $allow_zero -eq 0 ]] && return | ||
+ | echo -n " | ||
+ | elif [[ $size -lt 0 ]]; then | ||
+ | (( size=size*-1 )) | ||
+ | negative=1 | ||
+ | fi | ||
+ | |||
+ | (( size=size*${_FORMAT_SIZE_UNITS_FACTOR[$unit]} )) | ||
+ | for unit in " | ||
+ | [[ $size -lt ${_FORMAT_SIZE_UNITS_FACTOR[$unit]} ]] && continue | ||
+ | if [[ $size -eq ${_FORMAT_SIZE_UNITS_FACTOR[$unit]} ]]; then | ||
+ | size=1 | ||
+ | else | ||
+ | size=$( echo " | ||
+ | fi | ||
+ | [[ $negative -eq 1 ]] && size=$( echo " | ||
+ | echo -n " | ||
+ | return | ||
+ | done | ||
} | } | ||
</ | </ | ||
Ligne 181: | Ligne 300: | ||
<code bash> | <code bash> | ||
+ | === sprint === | ||
+ | |||
+ | **Pré-requis :** [[# | ||
+ | |||
+ | <code bash> | ||
+ | # | ||
+ | # Styled text printing helper | ||
+ | # | ||
+ | declare -rA COLORS=( | ||
+ | [black]=30 [red]=31 [green]=32 [brown]=33 [blue]=34 [purple]=35 [cyan]=36 [light_grey]=37 | ||
+ | [default]=39 [dark_grey]=90 [light_red]=91 [light_green]=92 [yellow]=93 [light_blue]=94 | ||
+ | [light_purple]=95 [light_cyan]=96 [white]=97 | ||
+ | ) | ||
+ | declare -rA BACKGROUND_COLORS=( | ||
+ | [black]=40 [red]=41 [green]=42 [brown]=43 [blue]=44 [purple]=45 [cyan]=46 [ligth_grey]=47 | ||
+ | [default]=49 [dark_grey]=100 [light_red]=101 [light_green]=102 [yellow]=103 [light_blue]=104 | ||
+ | [light_purple]=105 [light_cyan]=106 [white]=107 | ||
+ | ) | ||
+ | declare -rA TEXT_STYLES=( | ||
+ | [normal]=0 [bold]=1 [dim]=2 [italic]=3 [underline]=4 [blink]=5 [inverted_colors]=7 [hidden]=8 | ||
+ | [strikethrough]=9 | ||
+ | ) | ||
+ | declare -rA RESET_STYLES=( | ||
+ | [all]=0 [bold]=21 [dim]=22 [underline]=24 [blink]=25 [inverted_colors]=27 [hidden]=28 | ||
+ | ) | ||
+ | |||
+ | function sprint() { | ||
+ | local idx=1 opt value no_newline=0 output="" | ||
+ | local -a styles=() text=() | ||
+ | |||
+ | __sprint() { | ||
+ | [[ -n " | ||
+ | [[ " | ||
+ | output+=" | ||
+ | styles=() | ||
+ | output+=" | ||
+ | text=() | ||
+ | } | ||
+ | while [[ $idx -le $# ]]; do | ||
+ | opt=${!idx} | ||
+ | case $opt in | ||
+ | -c|--color) | ||
+ | [[ " | ||
+ | ((idx++)) | ||
+ | value=" | ||
+ | if [[ " | ||
+ | echo -n " | ||
+ | return 1 | ||
+ | fi | ||
+ | styles+=( " | ||
+ | ;; | ||
+ | -b|--bg) | ||
+ | [[ " | ||
+ | ((idx++)) | ||
+ | value=" | ||
+ | if [[ " | ||
+ | echo -n " | ||
+ | return 1 | ||
+ | fi | ||
+ | styles+=( " | ||
+ | ;; | ||
+ | -s|--style) | ||
+ | [[ " | ||
+ | ((idx++)) | ||
+ | value=" | ||
+ | if [[ " | ||
+ | echo -n " | ||
+ | return 1 | ||
+ | fi | ||
+ | styles+=( " | ||
+ | ;; | ||
+ | -r|--reset) | ||
+ | [[ " | ||
+ | ((idx++)) | ||
+ | value=" | ||
+ | if [[ " | ||
+ | echo -n " | ||
+ | return 1 | ||
+ | fi | ||
+ | output+=" | ||
+ | ;; | ||
+ | -n) | ||
+ | no_newline=1 | ||
+ | ;; | ||
+ | -h|--help) | ||
+ | echo " | ||
+ | echo " | ||
+ | implode ", " " | ||
+ | fold -w 53 -s | sed " | ||
+ | echo | ||
+ | echo " | ||
+ | implode ", " " | ||
+ | fold -w 53 -s | sed " | ||
+ | echo | ||
+ | echo " | ||
+ | implode ", " " | ||
+ | fold -w 53 -s | sed " | ||
+ | echo | ||
+ | echo " | ||
+ | implode ", " " | ||
+ | fold -w 53 -s | sed " | ||
+ | echo | ||
+ | echo " | ||
+ | echo " | ||
+ | ;; | ||
+ | *) | ||
+ | text+=( " | ||
+ | esac | ||
+ | ((idx++)) | ||
+ | done | ||
+ | __sprint | ||
+ | output+=" | ||
+ | if [[ " | ||
+ | echo -en " | ||
+ | else | ||
+ | echo -e " | ||
+ | fi | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | **Exemple :** | ||
+ | <code bash> | ||
+ | sprint -c red ' | ||
+ | </ | ||
+ | |||
+ | Résultat : | ||
+ | |||
+ | {{: | ||
===== Gestion des paramètres ===== | ===== Gestion des paramètres ===== | ||
Ligne 244: | Ligne 491: | ||
<code bash> | <code bash> | ||
declare -A PBARS | declare -A PBARS | ||
- | declare PBID | ||
# Create a progress bar | # Create a progress bar | ||
Ligne 251: | Ligne 497: | ||
# - total count (default: 100) | # - total count (default: 100) | ||
# - bar size (default: use all the width of the terminal with a minimum of 5 caracters) | # - bar size (default: use all the width of the terminal with a minimum of 5 caracters) | ||
- | # - the name of the variable use to store the progress bar ID (default: | + | # - the name of the variable use to store the progress bar ID (default: |
function pbar_create() { | function pbar_create() { | ||
- | | + | |
- | [ -n " | + | |
- | declare -n ID=" | + | |
- | # Generate the progress bar ID | + | |
- | ID=$( tr -dc A-Za-z0-9 </ | + | |
# Initialize progress bar information | # Initialize progress bar information | ||
- | PBARS[" | + | PBARS[" |
- | [ -n " | + | [ -n " |
- | [ -n " | + | [ -n " |
- | [ -n " | + | [ -n " |
- | PBARS[" | + | PBARS[" |
- | PBARS[" | + | PBARS[" |
+ | PBARS[" | ||
# Draw the progress bar for a first time | # Draw the progress bar for a first time | ||
- | pbar_draw $ID | + | pbar_draw |
} | } | ||
# Finish a progress bar | # Finish a progress bar | ||
# Arguments: | # Arguments: | ||
- | # - the ID of the progress bar (default: | + | # - the ID of the progress bar (default: |
function pbar_finish() { | function pbar_finish() { | ||
- | | + | |
- | unset ' | + | |
- | unset ' | + | # Force a last update of the progess bar |
- | unset ' | + | PBARS["${id}_END_TIME"]="$( date +%s )" |
- | unset ' | + | pbar_draw "$@" |
- | unset ' | + | |
+ | # Unset progress bar info | ||
+ | unset ' | ||
+ | unset ' | ||
+ | unset ' | ||
+ | unset ' | ||
+ | unset ' | ||
+ | unset ' | ||
echo | echo | ||
} | } | ||
Ligne 284: | Ligne 534: | ||
# Draw the progress bar | # Draw the progress bar | ||
# Arguments: | # Arguments: | ||
- | # - the ID of the progress bar (default: | + | # - the ID of the progress bar (default: |
# - extra message to display in the progress bar (before the ETA, optional) | # - extra message to display in the progress bar (before the ETA, optional) | ||
+ | # - all extra arguments will be use to compute the extra message using printf | ||
function pbar_draw() { | function pbar_draw() { | ||
- | [ -n "$1" ] && | + | |
+ | |||
+ | # Compute extra message | ||
+ | local extra=${2: | ||
+ | # shellcheck disable=SC2059 | ||
+ | [[ -n "$extra" | ||
# Only update progress bar one time by second | # Only update progress bar one time by second | ||
- | | + | |
- | [ $NOW -eq ${PBARS[${ID}_LAST_UPDATE]} ] && return | + | [[ "${PBARS[${id}_END_TIME]}" |
# Compute progress percentage | # Compute progress percentage | ||
- | | + | |
- | + | (( perc=${PBARS[${id}_CURRENT]}*100/ | |
- | # Compute duration, total duration, ETA & speed | + | |
- | let DURATION=NOW-${PBARS[${ID}_START_TIME]} | + | |
- | if [ ${PBARS[${ID}_CURRENT]} -gt 0 ] | + | |
- | then | + | |
- | let TOTAL_DURATION=DURATION*${PBARS[${ID}_TOTAL]}/ | + | |
- | SPEED=$( echo " | + | |
- | else | + | |
- | TOTAL_DURATION=0 | + | |
- | SPEED="?" | + | |
- | fi | + | |
- | let ETA=TOTAL_DURATION-DURATION | + | |
# Compute line without the progress bar | # Compute line without the progress bar | ||
- | | + | |
- | " | + | line_items=( |
+ | " | ||
" | " | ||
- | " | + | " |
- | ) | + | |
- | [ -n " | + | |
- | LINE+=( | + | |
- | "- ETA: $(format_duration $ETA)" | + | |
- | "- $( printf "(%s / %s, %s/s)" " | + | |
) | ) | ||
+ | [ -n " | ||
+ | |||
+ | # Add ETA (or total duration if finish) | ||
+ | if [[ " | ||
+ | # Compute duration, total duration, ETA & speed | ||
+ | local duration total_duration speed eta | ||
+ | (( duration=now-${PBARS[${id}_START_TIME]} )) | ||
+ | if [[ " | ||
+ | (( total_duration=duration*${PBARS[${id}_TOTAL]}/ | ||
+ | speed=$( bc <<< | ||
+ | else | ||
+ | total_duration=0 | ||
+ | speed="?" | ||
+ | fi | ||
+ | (( eta=total_duration-duration )) | ||
+ | |||
+ | line_items+=( | ||
+ | "- ETA: $(format_duration $eta)" | ||
+ | "- $( printf "(%s / %s, %s/s)" " | ||
+ | ) | ||
+ | else | ||
+ | local total_duration | ||
+ | (( total_duration=${PBARS[${id}_END_TIME]}-${PBARS[${id}_START_TIME]} )) | ||
+ | line_items+=( "- Total duration: $(format_duration $total_duration)" | ||
+ | fi | ||
# Compute progress bar length (if not configured) | # Compute progress bar length (if not configured) | ||
- | read -r TERM_HEIGHT TERM_WIDTH | + | |
- | | + | |
- | if [ $SIZE -eq 0 ] | + | |
- | | + | if [[ "$size" |
- | | + | |
- | | + | |
- | [ $SIZE -lt 5 ] && | + | |
fi | fi | ||
# Set progress bar text | # Set progress bar text | ||
- | | + | |
- | | + | |
- | | + | |
# Add line padding (if need) | # Add line padding (if need) | ||
- | | + | |
- | [ $LINE_PAD | + | |
# Compute & display line (strip the terminal width) | # Compute & display line (strip the terminal width) | ||
- | | + | |
- | echo -en "\r${LINE:0:$TERM_WIDTH}" | + | echo -en "\r${line:0:$term_width}" |
# Update last progress bar update time | # Update last progress bar update time | ||
- | PBARS[${ID}_LAST_UPDATE]=$NOW | + | PBARS[${id}_LAST_UPDATE]=$now |
} | } | ||
# Increment the progress bar | # Increment the progress bar | ||
# Arguments: | # Arguments: | ||
- | # - the ID of the progress bar (default: | + | # - the step (default: 1) |
+ | # - the ID of the progress bar (default: | ||
# - extra message to display in the progress bar (before the ETA, optional) | # - extra message to display in the progress bar (before the ETA, optional) | ||
# - all extra arguments will be use to compute the extra message using printf | # - all extra arguments will be use to compute the extra message using printf | ||
function pbar_increment() { | function pbar_increment() { | ||
- | | + | |
- | # Compute extra message | + | |
- | if [ -n " | + | |
- | then | + | |
- | EXTRA="$2" | + | |
- | shift 2 | + | |
- | [ $# -gt 0 ] && EXTRA=$( printf " | + | |
- | else | + | |
- | EXTRA="" | + | |
- | fi | + | |
# Increment the progress bar state | # Increment the progress bar state | ||
- | ((PBARS[${ID}_CURRENT]++)) | + | ((PBARS[${id}_CURRENT]+=step)) |
# Draw the progress bar | # Draw the progress bar | ||
- | pbar_draw | + | pbar_draw "${@:2}" |
} | } | ||
</ | </ | ||
Ligne 373: | Ligne 631: | ||
<code bash> | <code bash> | ||
pbar_create " | pbar_create " | ||
- | for i in $( seq 1 20 ) | + | for i in $( seq 1 20 ); do |
- | do | + | |
pbar_increment | pbar_increment | ||
sleep 0.1 | sleep 0.1 | ||
done | done | ||
pbar_finish | pbar_finish | ||
+ | </ | ||
+ | |||
+ | **Ajout d'info avant l'ETA :** | ||
+ | <code bash> | ||
+ | pbar_create " | ||
+ | for i in $( seq 1 20 ); do | ||
+ | pbar_increment "" | ||
+ | sleep 0.1 | ||
+ | done | ||
+ | pbar_finish "" | ||
</ | </ | ||
<note warning> | <note warning> |