Ceci est une ancienne révision du document !
Bash
Array
- déclaration :
array=( 1 2 3 )
oudeclare -a array=( 1 2 3 )
- déclaration d'un tableau associatif :
declare -A array=( ['key1']='value1' ['key2']='value2' ['key3']='value3' )
- déclaration d'un tableau en lecture seule :
declare -Ar ro_array=( […] )
oudeclare -ar ro_array=( […] )
- ajouter un élément :
array+=( 4 )
- ajouter un élément à un tableau associatif :
array+=( ['key']='value' )
- lister tous les éléments d'un tableau (=valeur dans le cas d'un tableau associatif) :
${array[@]}
- lister toutes les clés d'un tableau associatif :
${!array[@]}
- récupérer le nombre d'élements d'un tableau :
echo ${#array[@]}
Fonctions utiles
in_array
function in_array() { local needle=$1 el shift for el in "$@"; do [ "$el" = "$needle" ] && return 0 done return 1 }
Utilisation :
array=(1 2 3) in_array 1 ${array[@]} && echo IN in_array 5 ${array[@]} && echo OUT
is_empty
function is_empty() { [ $# -gt 0 ] && return 1 return 0 }
Utilisation :
array=(1 2 3) is_empty $array && echo empty ! is_empty $array && echo not empty
array_filter
function array_filter() { local values=() x=0 v for v in "$@"; do if [[ "$v" == "--" ]]; then x=1 elif [[ $x -eq 0 ]]; then values+=( "$v" ) else mapfile -t values < <( printf '%s\n' "${values[@]}" | grep -Ev "^${v}$" ) fi done printf '%s\n' "${values[@]}" }
Utilisation :
a=(a b c d e) array_filter ${a[@]} -- c e # Output: # a # b # d
array_intersect
function array_intersect() { local result_var=$1 declare -g "$result_var=()" shift local array1=() local array2=() local switch_to_array2=0 for v in "$@"; do if [ "$v" == "--" ]; then switch_to_array2=1 elif [ $switch_to_array2 -eq 0 ]; then array2+=( "$v" ) else array1+=( "$v" ) fi done for i in "${array1[@]}"; do for j in "${array2[@]}"; do if [[ $i == $j ]]; then declare -g "$result_var+=( \"$i\" )" break fi done done }
Utilisation :
a=(a b c d e) b=(c d) array_filter c ${a[@]} -- ${b[@]} echo ${c[@]} # Result: c d
implode
function implode() { local d=${1-} f=${2-} if shift 2; then printf %s "$f" "${@/#/$d}" fi }
Utilisation :
array=(1 2 3) echo $( implode "," "${array[@]}" ) # Output: 1,2,3 echo -e "- $( implode "\n- " "${array[@]}" )" # Output: # - 1 # - 2 # - 3
format_duration
function format_duration { local T=$1 local D=$((T/60/60/24)) local H=$((T/60/60%24)) local M=$((T/60%60)) local S=$((T%60)) (( $D > 0 )) && printf '%d days and ' $D printf '%02d:%02d:%02d' $H $M $S }
dump_ass_array
function dump_ass_array() { declare -n aarr="$1" echo "\"$1\" = {" for key in "${!aarr[@]}"; do printf ' "%s" => "%s"\n' "$key" "${aarr[$key]}" done echo "}" }
Utilisation :
declare -A myarray myarray[a]="b" myarray[c]="d" dump_ass_array myarray
var_dump
declare -p variableName
Gestion des paramètres
#!/bin/bash DEBUG=0 BIN_PATH="/bin/binary" EXTRA_ARGS=() function usage() { error="$1" [ -n "$error" ] && echo "$error" cat << EOF Usage : $(basename $0) [-d] [-b /path/to/binary] -b [path] Binary path (default: $BIN_PATH) -d Debug mode -X Enable bash tracing (=set -x) -h Show this message EOF [ -n "$error" ] && exit 1 exit 0 } function debug() { [ $DEBUG -eq 1 ] && >&2 echo -e "$( date '+%Y-%m-%d %H:%M:%S' ) - $@" } idx=1 while [ $idx -le $# ] do OPT=${!idx} case $OPT in -d) DEBUG=1 ;; -h) usage ;; -b) ((idx++)) BIN_PATH=${!idx} if [ ! -x "$BIN_PATH" ] then usage "Invalid binary path ($BIN_PATH)" fi ;; -X) set -x ;; *) EXTRA_ARGS+=( $OPT ) ;; esac ((idx++)) done debug "Extra args: ${EXTRA_ARGS[@]}"
Barre de progression
declare -A PBARS declare PBID # Create a progress bar # Arguments: # - the progress bar title (default: Progress) # - total count (default: 100) # - 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: PBID) function pbar_create() { # Define the name of the variable that will store the progress bar ID [ -n "$4" ] && PBAR_ID_VAR="$4" || PBAR_ID_VAR=PBID declare -n ID="$PBAR_ID_VAR" # Generate the progress bar ID ID=$( tr -dc A-Za-z0-9 </dev/urandom | head -c 3 ) # Initialize progress bar information PBARS["${ID}_START_TIME"]="$( date +%s )" [ -n "$1" ] && PBARS["${ID}_TITLE"]="$1" || PBARS["${ID}_TITLE"]="Progress" [ -n "$2" ] && PBARS["${ID}_TOTAL"]="$2" || PBARS["${ID}_TOTAL"]=100 [ -n "$3" ] && PBARS["${ID}_SIZE"]="$3" || PBARS["${ID}_SIZE"]=0 PBARS["${ID}_CURRENT"]=0 PBARS["${ID}_LAST_UPDATE"]=0 # Draw the progress bar for a first time pbar_draw $ID } # Finish a progress bar # Arguments: # - the ID of the progress bar (default: $PBID) function pbar_finish() { [ -n "$1" ] && ID=$1 || ID=$PBID unset 'PBARS[${ID}_START_TIME]' unset 'PBARS[${ID}_TITLE]' unset 'PBARS[${ID}_TOTAL]' unset 'PBARS[${ID}_CURRENT]' unset 'PBARS[${ID}_LAST_UPDATE]' echo } # Draw the progress bar # Arguments: # - the ID of the progress bar (default: $PBID) # - extra message to display in the progress bar (before the ETA, optional) function pbar_draw() { [ -n "$1" ] && ID=$1 || ID=$PBID # Only update progress bar one time by second NOW=$(date +%s) [ $NOW -eq ${PBARS[${ID}_LAST_UPDATE]} ] && return # Compute progress percentage let PERC=${PBARS[${ID}_CURRENT]}*100/${PBARS[${ID}_TOTAL]} # 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]}/${PBARS[${ID}_CURRENT]} SPEED=$( echo "scale=1; ${PBARS[${ID}_CURRENT]}/$DURATION"|bc ) else TOTAL_DURATION=0 SPEED="?" fi let ETA=TOTAL_DURATION-DURATION # Compute line without the progress bar LINE=( "${PBARS[${ID}_TITLE]}" "[]" "${PBARS[${ID}_CURRENT]}/${PBARS[${ID}_TOTAL]} (${PERC}%)" ) [ -n "$2" ] && LINE+=( "- $2" ) LINE+=( "- ETA: $(format_duration $ETA)" "- $( printf "(%s / %s, %s/s)" "$(format_duration $DURATION)" "$(format_duration $TOTAL_DURATION)" $SPEED )" ) # Compute progress bar length (if not configured) read -r TERM_HEIGHT TERM_WIDTH < <(stty size) SIZE=${PBARS[${ID}_SIZE]} if [ $SIZE -eq 0 ] then LINE_LENGTH=$( echo "${LINE[*]}"|wc -c ) SIZE=$[ $TERM_WIDTH - $LINE_LENGTH ] [ $SIZE -lt 5 ] && SIZE=5 fi # Set progress bar text let DONE=$PERC*$SIZE/100 let LEFT=$SIZE-$DONE LINE[1]="[$(printf "%${DONE}s"|tr ' ' '#')$(printf "%${LEFT}s"|tr ' ' '-')]" # Add line padding (if need) let LINE_PAD=TERM_WIDTH-${#LINE} [ $LINE_PAD -gt 0 ] && LINE+=( "$(printf "%${LINE_PAD}s")" ) # Compute & display line (strip the terminal width) LINE="${LINE[*]}" echo -en "\r${LINE:0:$TERM_WIDTH}" # Update last progress bar update time PBARS[${ID}_LAST_UPDATE]=$NOW } # Increment the progress bar # Arguments: # - the ID of the progress bar (default: $PBID) # - 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_increment() { [ -n "$1" ] && ID=$1 || ID=$PBID # Compute extra message if [ -n "$2" ] then EXTRA="$2" shift 2 [ $# -gt 0 ] && EXTRA=$( printf "$EXTRA" "$@" ) else EXTRA="" fi # Increment the progress bar state ((PBARS[${ID}_CURRENT]++)) # Draw the progress bar pbar_draw $ID "$EXTRA" }
Utilisation :
pbar_create "Test" 20 for i in $( seq 1 20 ) do pbar_increment sleep 0.1 done pbar_finish
La fonction format_duration est nécessaire.