-
Notifications
You must be signed in to change notification settings - Fork 0
/
utils.sh
executable file
·1965 lines (1764 loc) · 63.5 KB
/
utils.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/usr/bin/env bash
## @file
## @defgroup Colors Terminal colors
## @defgroup Effects Terminal effects
#-------------------------------------------------------------------------------
## @fn setColors()
## @details Import ANSI terminal colors. Implement foreground and background
## colors for 8/16 colors terminal ## emulators. These variables are exported
## that way, they are available to subprocesses as well.
## src.: http://misc.flogisoft.com/bash/tip_colors_and_formatting
## https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
## @note Bright colors are often the same for normal and light color versions.
#-------------------------------------------------------------------------------
function setColors() {
## @{
## @addtogroup Colors
## @var textBlack
## @brief Change text color to black.
# shellcheck disable=SC2034
export textBlack="[30m"
## @var textRed
## @brief Change text color to red.
export textRed="[31m"
## @var textGreen
## @brief Change text color to green.
export textGreen="[32m"
## @var textYellow
## @brief Change text color to yellow.
export textYellow="[33m"
## @var textBlue
## @brief Change text color to blue.
export textBlue="[34m"
## @var textMagenta
## @brief Change text color to magenta.
export textMagenta="[35m"
## @var textCyan
## @brief Change text color to cyan.
export textCyan="[36m"
## @var textLightGray
## @brief Change text color to light gray.
## LightGray might be the same as default, as default is sometimes gray or
## white depending on the emulator.
export textLightGray="[37m"
## @var textDefault
## @brief Change text color to default color.
export textDefault="[39m"
## @var textDarkGray
## @brief Change text color to dark gray.
export textDarkGray="[90m"
## @var textLightRed
## @brief Change text color to light red.
export textLightRed="[91m"
## @var textLightGreen
## @brief Change text color to light green.
export textLightGreen="[92m"
## @var textLightYellow
## @brief Change text color to light yellow.
export textLightYellow="[93m"
## @var textLightBlue
## @brief Change text color to light blue.
export textLightBlue="[94m"
## @var textLightMagenta
## @brief Change text color to light magenta.
export textLightMagenta="[95m"
## @var textLightCyan
## @brief Change text color to light cyan.
export textLightCyan="[96m"
## @var textWhite
## @brief Change text color to white.
export textWhite="[97m"
## @var backgroundBlack
## @brief Change background color to black.
export backgroundBlack="[40m"
## @var backgroundRed
## @brief Change background color to red.
export backgroundRed="[41m"
## @var backgroundGreen
## @brief Change background color to green.
export backgroundGreen="[42m"
## @var backgroundYellow
## @brief Change background color to yellow.
export backgroundYellow="[43m"
## @var backgroundBlue
## @brief Change background color to blue.
export backgroundBlue="[44m"
## @var backgroundMagenta
## @brief Change background color to magenta.
export backgroundMagenta="[45m"
## @var backgroundCyan
## @brief Change background color to cyan.
export backgroundCyan="[46m"
## @var backgroundLightGray
## @brief Change background color to light gray.
export backgroundLightGray="[47m"
## @var backgroundDefault
## @brief Change background color to the default color.
export backgroundDefault="[49m"
## @var backgroundDarkGray
## @brief Change background color to dark gray.
export backgroundDarkGray="[100m"
## @var backgroundLightRed
## @brief Change background color to light red.
export backgroundLightRed="[101m"
## @var backgroundLightGreen
## @brief Change background color to light green.
export backgroundLightGreen="[102m"
## @var backgroundLightYellow
## @brief Change background color to light yellow.
export backgroundLightYellow="[103m"
## @var backgroundLightBlue
## @brief Change background color to light blue.
export backgroundLightBlue="[104m"
## @var backgroundLightMagenta
## @brief Change background color to light magenta.
export backgroundLightMagenta="[105m"
## @var backgroundLightCyan
## @brief Change background color to light cyan.
export backgroundLightCyan="[106m"
## @var backgroundWhite
## @brief Change background color to white.
export backgroundWhite="[107m"
## @var colorReset
## @brief Reset the colors to the default color defined by the emulator.
## @note Resetting the colors also resets the effect back to the default.
export colorReset="[0m"
## @}
}
#-------------------------------------------------------------------------------
## @fn set_colors()
## @details Simple alias to setColors
#-------------------------------------------------------------------------------
function set_colors() {
setColors
}
#-------------------------------------------------------------------------------
## @fn unsetColors()
## @details Simply unset the exported colors
#-------------------------------------------------------------------------------
function unsetColors() {
unset textBlack
unset textRed
unset textGreen
unset textYellow
unset textBlue
unset textMagenta
unset textCyan
unset textLightGray
unset textDefault
unset textDarkGray
unset textLightRed
unset textLightGreen
unset textLightYellow
unset textLightBlue
unset textLightMagenta
unset textLightCyan
unset textWhite
unset backgroundBlack
unset backgroundRed
unset backgroundGreen
unset backgroundYellow
unset backgroundBlue
unset backgroundMagenta
unset backgroundCyan
unset backgroundLightGray
unset backgroundDefault
unset backgroundDarkGray
unset backgroundLightRed
unset backgroundLightGreen
unset backgroundLightYellow
unset backgroundLightBlue
unset backgroundLightMagenta
unset backgroundLightCyan
unset backgroundWhite
unset colorReset
}
#-------------------------------------------------------------------------------
## @fn unset_colors()
## @details Simple alias to unsetColors
#-------------------------------------------------------------------------------
function unset_colors() {
unsetColors
}
#-------------------------------------------------------------------------------
## @fn setEffects()
## @details Import ANSI terminal effects.
#-------------------------------------------------------------------------------
function setEffects() {
## @{
## @addtogroup Effects
## @var effectBright
## @brief Increase the color brightness.
export effectBright="[1m"
## @var effectDim
## @brief Dicrease the color of the text (white becomes gray, etc.).
export effectDim="[2m"
## @var effectItalic
## @brief Put the text in italic.
export effectItalic="[3m"
## @var effectUnderline
## @brief Put a line under the text.
export effectUnderline="[4m"
## @var effectBlink
## @brief Make the text blinking (not supported in most of the terminals).
export effectBlink="[5m"
## @var effectReverse
## @brief Put the text in reverse color.
export effectReverse="[7m"
## @var effectHidden
## @brief Hide the text (useful for passwords).
export effectHidden="[8m"
## @var effectStrikeThrough
## @brief Add a line through the text.
export effectStrikeThrough="[9m"
## @var effectBrightReset
## @brief Reset the color brightness effect.
export effectBrightReset="[21m"
## @var effectDimReset
## @brief Reset the reduced color of the text.
export effectDimReset="[22m"
## @var effectItalicReset
## @brief Remove the italic effect of the text.
export effectItalicReset="[23m"
## @var effectUnderlineReset
## @brief Remove the line under the text.
export effectUnderlineReset="[24m"
## @var effectBlinkReset
## @brief Remove the blinking of the text.
export effectBlinkReset="[25m"
## @var effectReverseReset
## @brief Reset the reverse color effect.
export effectReverseReset="[27m"
## @var effectHiddenReset
## @brief Reset the hidden text effect.
export effectHiddenReset="[28m"
## @var effectStrikeThroughReset
## @brief Remove the a line through the text.
export effectStrikeThroughReset="[29m"
## @var effectReset
## @brief Reset the effects to the default ones defined by the emulator.
## @note Resetting the effects will also resets the colors back to the default.
export effectReset="[0m"
## @}
}
#-------------------------------------------------------------------------------
## @fn set_effects()
## @details Simple alias to setEffects
#-------------------------------------------------------------------------------
function set_effects() {
setEffects
}
#-------------------------------------------------------------------------------
## @fn unsetEffects()
## @details Import ANSI terminal effects.
#-------------------------------------------------------------------------------
function unsetEffects() {
unset effectBright
unset effectDim
unset effectItalic
unset effectUnderline
unset effectBlink
unset effectReverse
unset effectHidden
unset effectStrikeThrough
unset effectBrightReset
unset effectDimReset
unset effectItalicReset
unset effectUnderlineReset
unset effectBlinkReset
unset effectReverseReset
unset effectHiddenReset
unset effectStrikeThroughReset
unset effectReset
}
#-------------------------------------------------------------------------------
## @fn unset_effects()
## @details Simple alias to unsetEffects
#-------------------------------------------------------------------------------
function unset_effects() {
unsetEffects
}
#-------------------------------------------------------------------------------
## @fn getDate()
## @details Get date and time with nanoseconds (when supported, which isn't on
## BSD).
## @return In $retval, the string date under the format 8601.
## @retval 0 If no issue occurred.
## @retval 1 If an issue occurred.
#-------------------------------------------------------------------------------
function getDate() {
unset retval
if ! checkDeps 'date'; then
return 1
fi
# Splitting declaration and assignation on two lines prevents SC2155
local date
date="$(date "+%Y-%m-%dT%H:%M:%N")"
# If nanoseconds are not supported, the final string contains ":N".
if strpos "$date" ":N"; then
date=$(date "+%Y-%m-%dT%H:%M")
fi
retval="$date"
return 0
}
#-------------------------------------------------------------------------------
## @fn get_date()
## @details Simple alias to getDate
#-------------------------------------------------------------------------------
function get_date() {
getDate
}
#-------------------------------------------------------------------------------
## @fn log()
## @details If logger is present, print explicitely a string in the logs with
## the priority specified.
## @param $msg The message to send to the logs.
## @param $level Level of the error corresponds to the priority code used in
## @param $script The name of the script responsible of the issue
## traditional syslog implementations. The priority can be prefixed by a
## facility which is a code used to specify the type of the program.
## src.: https://en.wikipedia.org/wiki/Syslog#Facility
## If $level is not specified, it defaults to "user.err".
#-------------------------------------------------------------------------------
function log() {
if [[ -z "$2" ]]; then
local level="user.err"
else
local level="$2"
fi
if type logger >/dev/null 2>&1; then
if [[ -z "$3" ]]; then
## See getScriptName() to know more why we use BASH_SOURCE here.
logger -p "$level" "${BASH_SOURCE[ ${#BASH_SOURCE[@]} - 1 ]##*/}: $1"
else
logger -p "$level" "$3: $1"
fi
fi
}
#-------------------------------------------------------------------------------
## @fn echoerr()
## @details Simply print a string on stderr.
## @param $string The string to display on stderr.
#-------------------------------------------------------------------------------
function echoerr() {
echo "$@" 1>&2;
}
#-------------------------------------------------------------------------------
## @fn echoErr()
## @details Simple alias to echoerr
#-------------------------------------------------------------------------------
function echoErr() {
echoerr "$@"
}
#-------------------------------------------------------------------------------
## @fn info()
## @details Print an info message. If the script is run in the background, put
## a warning message in the system logger. If the script is redirected to a file
## or run interactively, format the info message accordingly. The name of the
## script is prefixed to the message (thus not the name of the sourced library).
## @param $msg The message to display as info.
## @retval 0 Always return 0.
#-------------------------------------------------------------------------------
function info() {
unset retval
getScriptName
local scriptName="$retval"
getDate
local date="$retval"
unset retval
if isRunInBackground $$; then
log "$*" user.info "$scriptName[$$]"
fi
# Even if run in the background, this does not mean the output is
# redirected. We can thus continue.
# Test if the output is redirected
# http://stackoverflow.com/a/26761733/3514658
if [[ ! -t 1 ]]; then
echo "[INFO] $date $scriptName[$$]: $*"
return 0
fi
setColors
setEffects
echo "[${textGreen}${effectBright}+${colorReset}] $*"
unsetColors
unsetEffects
return 0
}
#-------------------------------------------------------------------------------
## @fn warning()
## @details Print a warning message. (See info() for details).
## @param $msg The message to display as warning.
## @retval 0 Always return 0.
#-------------------------------------------------------------------------------
function warning() {
unset retval
getScriptName
local scriptName="$retval"
getDate
local date="$retval"
unset retval
if isRunInBackground $$; then
log "$*" user.warning "$scriptName[$$]"
fi
if [[ ! -t 1 ]]; then
echo "[WARNING] $date $scriptName[$$]: $*"
return 0
fi
setColors
setEffects
echo "[${textYellow}${effectBright}!${colorReset}] $*"
unsetColors
unsetEffects
return 0
}
#-------------------------------------------------------------------------------
## @fn error()
## @details Print an error message. (See info() for details).
## @param $msg The message to display as error.
## @retval 0 Always return 0.
#-------------------------------------------------------------------------------
function error() {
unset retval
getScriptName
local scriptName="$retval"
getDate
local date="$retval"
unset retval
if isRunInBackground $$; then
log "$*" user.err "$scriptName[$$]"
fi
if [[ ! -t 2 ]]; then
echoerr "[ERROR] $date $scriptName[$$]: $*"
return 0
fi
setColors
setEffects
echoerr "[${textRed}${effectBright}x${colorReset}] $*"
unsetColors
unsetEffects
return 0
}
#-------------------------------------------------------------------------------
## @fn die()
## @details Print an error message and exit as an error. (See info() for
## details).
## @param $msg The message to display as error.
## @retval 1 Always return 1.
#-------------------------------------------------------------------------------
function die() {
unset retval
getScriptName
local scriptName="$retval"
getDate
local date="$retval"
unset retval
if isRunInBackground $$; then
log "$*" user.err "$scriptName[$$]"
fi
if [[ ! -t 2 ]]; then
echoerr "[FATAL] $date $scriptName[$$]: $*"
return 0
fi
setColors
setEffects
echoerr "[${textRed}${effectBright}x${colorReset}] $*"
unsetColors
unsetEffects
exit 1
}
#-------------------------------------------------------------------------------
## @fn confirm()
## @details Ask the user if he wants to continue or not, with the message we
## specified.
## @param $string The question to ask to the user. This string can be splitted
## in several arguments if the question is too long. That way, the text can we
## hard wrapped in the text editor of the user wanting to use this function.
## @return In $retval, true if the user has confirmed. false if the user hasn't.
## @retval 0 If the user has confirmed.
## @retval 1 If the user has not confirmed.
#-------------------------------------------------------------------------------
function confirm() {
unset retval
# String needed when we are cutting our user message in several arguments to
# hard wrap our source file in our text editor.
local string="$*"
setColors
setEffects
read -p "[${textBlue}${effectBright}?${colorReset}] $string " -n 1 -r
unsetColors
unsetEffects
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
retval=true
return 0
else
retval=false
return 1
fi
}
#-------------------------------------------------------------------------------
## @fn isArgument()
## @details Check if the string is an argument using the format "--argument"
## or "-a".
## This function must be used directy like in "if isArgument "--dest"; then".
## @param $string The string to check as an argument.
## @return In $retval, true if this is an argument, false if it isn't.
## @retval 0 If this is an argument.
## @retval 1 If this is not an argument.
#-------------------------------------------------------------------------------
function isArgument() {
unset retval
# ^ at the start of the regex causes the expression to be anchored at the
# start of a line. Always put regex OUTSIDE quotes.
if [[ "$1" =~ ^--[a-zA-Z]+(-[a-zA-Z]+)*$ || "$1" =~ ^-[a-zA-Z]$ ]]; then
retval=true
return 0
fi
retval=false
return 1
}
#-------------------------------------------------------------------------------
## @fn is_argument()
## @details Simple alias to isArgument
#-------------------------------------------------------------------------------
function is_argument() {
isArgument "$@"
}
#-------------------------------------------------------------------------------
## @fn checkDeps()
## @details Check if the specified commands exist in the PATH.
## @param $string A space separated list of items where each correspond to
## a command to check in the PATH.
## @return In $retval, an array of commands missing when the requirements are
## unmet or an empty array if the requirements are met.
## @retval 0 If the requirements are met.
## @retval 1 If the requirements are unmet.
#-------------------------------------------------------------------------------
function checkDeps() {
unset retval
local i
for i in $1; do
if ! type "$i" >/dev/null 2>&1; then
# ShellCheck thinks this is an associative array, which isn't.
# shellcheck disable=SC2190
retval+=("$i")
fi
done
unset i
if ((${#retval[@]} == 0)); then
return 0
fi
return 1
}
#-------------------------------------------------------------------------------
## @fn check_deps()
## @details Simple alias to checkDeps
#-------------------------------------------------------------------------------
function check_deps() {
checkDeps "$@"
}
#-------------------------------------------------------------------------------
## @fn requireDeps()
## @details Display the commands not available.
## @param $string A space separated list of items where each correspond to
## a command to check in the PATH.
## @retval 0 If the requirements are met.
## @retval 1 If the requirements are unmet.
#-------------------------------------------------------------------------------
function requireDeps() {
unset retval
if ! checkDeps "$*"; then
local msg
if ((${#retval[@]} >= 2)); then
msg='The commands '
if ((${#retval[@]} == 2)); then
msg+="'${retval[0]}' and '${retval[1]}'"
else
for ((i = 0; i < ${#retval} - 2; i++)); do
msg+="'${retval[i]}', "
done
msg+="'${retval[$i]}' and "
((i++))
msg+="'${retval[$i]}' "
fi
msg+=" are not installed. Aborted."
else
msg="The command '${retval[0]}' is not installed. Aborted."
fi
die "${FUNCNAME[1]}: $msg"
fi
return 0
}
#-------------------------------------------------------------------------------
## @fn require_deps()
## @details Simple alias to requireDeps
#-------------------------------------------------------------------------------
function require_deps() {
requireDeps "$@"
}
#-------------------------------------------------------------------------------
## @fn var_dump()
## @details Dumps information about the variable passed as argument.
## @param $var The variable name (thus without the dollar char $). If the
## dollar sign is used, the value will be used instead.
## @note This function makes use of the evil eval statement. While the latter
## has been sanitized, the check is rather naive. We initially used the retval
## statement but this was rather cumbersome for the end user. The latter had
## always to backup its retval variable to check another one.
## @retval 0 Always return 0.
#-------------------------------------------------------------------------------
function var_dump() {
# Need to split declaration and assignation, otherwise the return value is
# incorrect.
local varType
while (($#)); do
local var="$1"
shift
local -i i=0
# Try to sanitize the evil use of eval. (If you're reading this, sorry).
if strpos "$var" ";" ||
strpos "$var" "(" ||
strpos "$var" ")" ||
strpos "$var" "$" ||
strpos "$var" "{" ||
strpos "$var" "}"; then
continue
fi
# If the declare statement fails (e.g. trying to call it directly on
# a string, or on a number, without using a variable name).
if ! varType=$(declare -p "$var" 2>/dev/null); then
# Cast to a number if we assume this is a number
if isNumber "$var"; then
echo "int($var)"
else
# Unable to check if the argument is a string by checking if the
# argument is passed with " or ' as these chars are interpreted by
# the shell.
echo "string(${#var}) \"$var\""
fi
continue
fi
# Since Bash 4.3, a reference to another variable can be added, browse all
# the references in order to get the parent type.
# src.: http://stackoverflow.com/a/42877229/3514658
local reg='^declare -n [^=]+=\"([^\"]+)\"$'
while [[ $varType =~ $reg ]]; do
varType=$(declare -p "${BASH_REMATCH[1]}")
done
case "${varType#declare -}" in
a*)
local -i len=0
eval 'len=${#'"$var"'[@]} 2>/dev/null'
echo "array(${len}) {"
for ((i = 0; i < len; i++)); do
echo " [$i]=>"
echo -n " "
eval 'var_dump "${'"$var"'[i]}"'
done
echo "}"
;;
A*)
# Needs Bash 4+
# src.: http://stackoverflow.com/a/3467959/3514658
local keys=()
eval 'keys=(${!'"$var"'[@]}) 2>/dev/null'
local -i len=${#keys[@]}
echo "array(${len}) {"
for ((i = 0; i < len; i++)); do
local value
eval 'value=${'"$var"'[${keys[i]}]}'
if isNumber "${keys[i]}"; then
echo " [${keys[i]}]=>"
else
echo " [\"${keys[i]}\"]=>"
fi
echo -n " "
var_dump "$value"
done
echo "}"
;;
i*)
echo "int($var)"
;;
x*)
echo "export(${#var}) \"$var\""
;;
*)
echo "string(${#var}) \"$var\""
;;
esac
done
}
#-------------------------------------------------------------------------------
## @fn varDump()
## @details Simple alias to var_dump
#-------------------------------------------------------------------------------
function varDump() {
var_dump "$@"
}
#-------------------------------------------------------------------------------
## @fn progress()
## @details Print the progression indicator where the number are padded to the
## right on the specified max value. %%PERCENT%% values can be changed to$
## '%% PERCENT%%' (prefixed by a space character) if we want leading spaces or
## '%%0PERCENT%%' (zero character) to have leading 0.
## @param $current The current progress value (must be a number).
## @param $max The maximum progress value corresponding to 100% (must be a
## number).
## @param $msg The message to print where %%MIN%%, %%MAX%% and %%PERCENT%%
## placeholders will be replaced by the current and maximum value.
## @return In $retval, the correct formatted string, or an empty string if
## there was an issue.
## @retval 0 If no issue occurred.
## @retval 1 If an issue occurred.
#-------------------------------------------------------------------------------
function progress() {
# Number needs to be a string, otherwise further display changes will be
# discarded as Bash will remove the leading 0 and padding.
local number
local message="$3"
local -i percent
if ! isNumber "$1"; then
# shellcheck disable=SC2178
retval=""
return 1
fi
if ! isNumber "$2"; then
# shellcheck disable=SC2178
retval=""
return 1
fi
if strpos "$message" "%% CURRENT%%"; then
printf -v number "%${#2}s" "$1"
message=${message/\%\% CURRENT\%\%/$number}
elif strpos "$message" "%%0CURRENT%%"; then
printf -v number "%0${#2}d" "$1"
message=${message/\%\%0CURRENT\%\%/$number}
else
message=${message/\%\%CURRENT\%\%/$1}
fi
if strpos "$message" "%% MAX%%"; then
printf -v number "%${#2}s" "$2"
message=${message/\%\% MAX\%\%/$number}
elif strpos "$message" "%%0MAX%%"; then
printf -v number "%0${#2}d" "$2"
message=${message/\%\%0MAX\%\%/$number}
else
message=${message/\%\%MAX\%\%/$2}
fi
# POSIX shell does not support float. Need to use bc otherwise.
# Compute percent and reuse same variable
percent=$((($1 * 100) / $2))
# To strip zeroes padding use $((10#$min)), but we prefer printf in order
# to store in a variable without using subshells. Also using printf to
# store in the same variable as the one we read from does not work. The
# variable where we will store the result needs to be different.
if strpos "$message" "%% PERCENT%%"; then
printf -v number "%3s" "$percent"
message=${message/\%\% PERCENT\%\%/$number}
elif strpos "$message" "%%0PERCENT%%"; then
printf -v number "%03d" "$percent"
message=${message/\%\%0PERCENT\%\%/$number}
else
message=${message/\%\%PERCENT\%\%/$percent}
fi
unset retval
# shellcheck disable=SC2178
retval="$message"
return 0
}
#-------------------------------------------------------------------------------
## @fn isNumber()
## @details Check if the string is a number (positive, negative and decimal are
## taken into account.
## @param $string The string to check if this is a number.
## @return In $retval, true f the string is a number, false if it isn't.
## @retval 0 If the string is a number.
## @retval 1 If the string is not a number.
#-------------------------------------------------------------------------------
function isNumber() {
unset retval
if [[ "$1" =~ ^-?[0-9]+([.][0-9]+)?$ ]]; then
# shellcheck disable=SC2178
retval=true
return 0
fi
# shellcheck disable=SC2178
retval=false
return 1
}
#-------------------------------------------------------------------------------
## @fn is_number()
## @details Simple alias to isNumber
#-------------------------------------------------------------------------------
function is_number() {
isNumber "$@"
}
#-------------------------------------------------------------------------------
## @fn isNumberPositive()
## @details Check if the string is a number (positive, negative and decimal are
## taken into account.
## @param $string The string to check if this is a number.
## @return In $retval, true f the string is a number, false if it isn't.
## @retval 0 If the string is a number.
## @retval 1 If the string is not a number.
#-------------------------------------------------------------------------------
function isNumberPositive() {
unset retval
if [[ "$1" =~ ^\+?[0-9]+([.][0-9]+)?$ ]]; then
# shellcheck disable=SC2178
retval=true
return 0
fi
# shellcheck disable=SC2178
retval=false
return 1
}
#-------------------------------------------------------------------------------
## @fn is_number_positive()
## @details Simple alias to isNumberPositive
#-------------------------------------------------------------------------------
function is_number_positive() {
isNumberPositive "$@"
}
#-------------------------------------------------------------------------------
## @fn strpos()
## @details Find the position of the first occurrence of a substring in a string
## @param $string The haystack string to search in.
## @param $pattern The needle string to search for.
## @param $offset If specified, search will start this number of characters
## counted from the beginning of the string. If the offset is negative, the
## search will start this number of characters counted from the end of the
## string.
## @return In $retval, the position starting from 0 where the pattern was
## found, -1 if this wasn't found. false if an error occurred.
## @retval 0 If the pattern was found.
## @retval 1 If the pattern was not found.
#-------------------------------------------------------------------------------
function strpos() {
unset retval
local string="$1"
local pattern="$2"
if [[ -z "$3" ]]; then
local -i offset=0
else
local -i offset="$3"
fi
if ((offset < 0)); then
if ((-1 * offset > ${#string})); then
# shellcheck disable=SC2178
retval=false
return 1
fi
string=${string:${#string} - offset}
else
string=${string:$offset}
fi
# The initial state of the automaton (the table of failure function)
# corresponding to the empty string.
local -i n=${#string}
local -i m=${#pattern}
# The initial state of the automaton (the table of failure function)
# corresponding to the empty string.
local -i i=0
# The first character of the string
local -i j=0
__kmpBuildFailureFunction "$pattern"
local ff=("${retval[@]}")
unset retval
while true; do
if ((j == n)); then
break
fi
if [[ "${string:j:1}" == "${pattern:i:1}" ]]; then
((i++))
((j++))
if ((i == m)); then
# shellcheck disable=SC2178
retval=$((j - m))
break
fi
elif ((i > 0)); then
i=${ff[i]}
else
((j++))
fi
done
# shellcheck disable=SC2128
if [[ -z "$retval" ]]; then
# shellcheck disable=SC2178
retval=-1
return 1
fi
((retval+=offset))
return 0
}
#-------------------------------------------------------------------------------
## @fn strPos()
## @details Simple alias to strpos
#-------------------------------------------------------------------------------
function strPos() {
strpos "$@"
}