-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfloatversion
executable file
·529 lines (476 loc) · 24.3 KB
/
floatversion
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
#!/usr/bin/env bash
# (c) Alex Genovese https://github.com/TuxVinyards/floatversion
# License: MIT
# Extracts point separated numbers, or semantic version numbers with optional suffixes,
# and other common variations upon, from a given string or text list
# Script outputs as true/false test, as single item, or as space or line separated list.
# Sorts to unique or listed entries, or to latest version in std numeric or sem. ver.
# Up-to-date versions of Bash, Grep and JQ should be present.
# MacOS requires Homebrew versions of Bash and Grep and also requires JQ
# FloatVersion uses'jq' for sorting suffixes, unless specified.
# Various versioning systems exist:
# See https://en.wikipedia.org/wiki/Software_versioning and http://semver.org/
# For this script: x.xx.xx-suffix > major.minor.point and with optionals as -beta.01 etc
# Non-major numbers are padded to 2dp to make easier reading in file managers
# Current Version 1.02.02 > set locally in function case statements
# POSIX and Mac/HomeBrew compliant initial Bash test:
if [ ! "$(command -v bash)" ] || ! bash --version | grep bash | grep -qEo '[ ]+[5-9]+[.]' ; then
echo; echo " Sorry, you need Bash, probably 5.0 or newer to run this script."; echo
echo " FloatVersion has only been tested on up-to-date versions of Bash"; echo
echo " Certain elements require at least ver 4.2 .... "; echo
if [ "$(uname -o)" = "Darwin" ]; then echo " An update is needed via HomeBrew"; echo ; fi
if [ "$(command -v bash)" ]; then echo " Your version: "; echo ; bash --version ; echo ; fi
fi
# Use C.UTF-8 where possible as has more locale See https://wiki.archlinux.org/title/Locale
# NB if EMBEDDING, make sure that this or LC_ALL=C.UTF-8 or LC_ALL=C is present in the main script
if grep -sqi 'C.utf8' <<< "$(locale -a)"; then export "LC_NUMERIC=C.UTF-8" ; export "LC_COLLATE=C.UTF-8"
else export "LC_NUMERIC=C" ; export "LC_COLLATE=C"
fi
# MacOS requires Homebrew additions of Bash and of Grep. Also needs JQ.
if [[ "$(uname -o)" == "Darwin" ]]; then
if [[ ! -d "/usr/local/opt/grep/libexec/gnubin" ]]; then
echo; echo " Sorry, you need to update 'grep' via HomeBrew to run this script."; echo
elif ! grep -q 'gnubin' <<< "$PATH" ; then export PATH="/usr/local/opt/grep/libexec/gnubin:$PATH"
fi
if [[ ! -d "/usr/local/Cellar/jq" ]]; then
echo; echo " Sorry, you need to add 'jq' via HomeBrew to run this script."; echo
fi
fi
# Flag for dev analysis, set =1 to use compact version when running from script OR -C / --compact as $1
CompactVersion=
# Optional output array:
# When embedding in Bash scripts, the optional array '${fvOutputArr[*]}' is by default set as global
# In standalone full mode, setting a path here will enable output in plain text column format
# to a transfer file eg '/tmp/fv-arr.txt' that can be be mapped by most scripts
FvArrFilePath=
##
# FULL VERSION for embedding in larger projects, has the verbose mode ready built in.
# Named differently to enable easy separation when it is being used inside the standalone script.
# When pasting the full version, it should be renamed to 'floatversion', the same as with the compact one.
# Using the standard format of < floatversion --options "quoted-input-source" > will ensure that any code call
# will auto-route to floatversion as a standalone dependency if the function is not present,
# or if later switching to compact, or if wanting to re-use code elsewhere.
float_version_from_string () {
show_help () {
printf "
floatversion --options \"quoted-input-source\"
Extracts point separated numbers, or semantic version numbers with optional suffixes,
and other common variations upon, from a given string or text-file
-h | --help show help
-V | --version show version
-c | --col show list as column instead of string
-s | --space use single spaced string (for alternative machine reading)
-r | --rev show list in reverse order
-a | --all show all extracted values, not just unique
-n | --num sort by standard numbering, not versioning
-f | --full check for additional sem. ver. suffixes, eg. -beta
-F | --filter contains given items -F \"string string string\"
-S | --starts starting with -S \"string string string\"
-D | --delete doesn't contain: -D \"string string string\"
-M | --max Outputs the single highest/latest value in the list and with '-r' the lowest/earliest,
with integer shows top or bottom of total list eg. -M 3 is top 3 and -M 3 -r the bottom.
-RM [int] Outputs the single lowest/earliest value in the list. With integer, as -M but
reverses only the M filter set, not the list, eg. -M 3 > 3 2 1 -RM 3 > 1 2 3
also accepts '-r' to reverse a lowest set filter ...
-g | --gt A > B, returns true/false eg. if fv -g \"A B\"; then .. (.nums or sem ver)
Normally quiet and to be tested. Use -v for screen output or piping.
-v | --verbose for problem output, show algorithm sequences (full version only)
--sort-v use sort -V (if present) in preference to the default jq methods
--no-svb no falling back to 'jq' if 'sort -V' is unavailable, show error instead
Without options, produces a single sorted string of all unique items found
Filters output as string, column or max. Post-output grep requires columns.
Tests show 'jq' sort methods as more reliable than 'sort -V' esp. with alpha suffixes
All cases, returns false if none. Direct \'2>/dev/null\' to quieten messages.
License: MIT Copyright (c) Alex Genovese
Further Usage/Help/Details @ https://github.com/TuxVinyards/floatversion
"
}
local ShowAsCol=
local ShowAsStr=
local SingleSpace=
local ShowMax=
local TopMax=
local RevMax=
local TopShow=
local ShowAll=
local ShowRev=
local SortNum=
local GrepFull=
local InputText=
local Nums=
local NumsCount=
local FilterString=
local StartString=
local DeleteString=
local GTcompare=
local Verbose=
local UseSortV=
local NoSortVfallback=
local CurrentVersion=
local LatestVersion=
declare -a NumArrTemp
declare -a NumArrSorted
declare -a FilterArr
declare -a StartArr
declare -a DeleteArr
declare -a SelectArrTemp
declare -ga fvOutputArr
while [[ "$1" ]] ; do
case "$1" in
-h|--help)
show_help ; return 0 ;;
-V|--version)
CurrentVersion="1.02.02"
printf "\n CurrentVersion: %s" "$CurrentVersion"
printf "\n\n Checking for updates.... "
LatestVersion="$(floatversion -M "$(curl -sf --max-time 5 "https://github.com/TuxVinyards/floatversion/releases" | grep 's/tag')" 2>/dev/null)"
if [[ $LatestVersion ]]; then
printf "LatestVersion: %s " "$LatestVersion"
if floatversion --gt "$LatestVersion $CurrentVersion" 2>/dev/null; then printf " UPGRADEABLE "
else printf " Up-to-Date "
fi
else printf "connection/data not available"
fi
printf "\n\n (c) Alex Genovese https://github.com/TuxVinyards/floatversion \n\n"
return 0 ;;
-c|--col)
ShowAsCol=1 ; shift ;;
-s|--space )
SingleSpace=1 ; shift ;;
-r|--rev)
ShowRev=1 ; shift ;;
-a|--all)
ShowAll=1 ; shift ;;
-n|--num)
SortNum=1 ; shift ;;
-f|--full)
GrepFull=1 ; shift ;;
-F|--filter)
[[ ! $2 ]] && show_help && return 1
FilterString="$2" ; shift 2 ;;
-S|--start)
[[ ! $2 ]] && show_help && return 1
StartString="$2" ; shift 2 ;;
-D|--delete)
[[ ! $2 ]] && show_help && return 1
DeleteString="$2" ; shift 2 ;;
-M|--max)
ShowMax=1 ; shift
[[ "$1" == [1-9] || "$1" == [1-9][0-9] ]] && { TopMax="$1"; ShowMax=; shift; } ;;
-RM)
ShowMax=1 ; RevMax=1 ; shift
[[ "$1" == [1-9] || "$1" == [1-9][0-9] ]] && { TopMax="$1"; ShowMax=; shift; } ;;
-g|--gt)
GTcompare=1; shift ;;
-v|--verbose)
Verbose=1 ; shift ;;
--sort-v)
UseSortV=1 ; shift ;;
--no-svb)
NoSortVfallback=1 ; shift ;;
*)
if [[ "$1" == '-'* ]]; then
printf "\n ERROR: '%s' not recognised \n" "$1" >&2
show_help >&2 ; return 1
elif [[ $InputText ]]; then
printf "\n ERROR: QUOTED Input String or Text File Name should be given only once \n" >&2
show_help >&2 ; return 1
else
InputText="$1" ; shift
fi ;;
esac
done
# if input is file name, then read file,
# sanitize and make sure that all input is a safe line separated list, or becomes one
[[ -e "$InputText" ]] && InputText="$(cat -vet "$InputText")"
InputText="$(tr ';' ' ' <<< "$InputText" | tr '$' ' \n' | tr ' ' '\n' | grep -sE '[[:print:]]')"
if [[ ! $InputText ]]; then
printf "\n ERROR: no input found. Is input present as a quoted element? \n" >&2
show_help >&2 ; return 1
fi
[[ $FilterString ]] && mapfile -t FilterArr <<< "$(tr ' ' '\n' <<< "$FilterString")"
[[ $StartString ]] && mapfile -t StartArr <<< "$(tr ' ' '\n' <<< "$StartString")"
[[ $DeleteString ]] && mapfile -t DeleteArr <<< "$(tr ' ' '\n' <<< "$DeleteString")"
if [[ $ShowMax ]]; then ShowAsStr= ; ShowAsCol=
elif [[ $ShowAsCol ]]; then ShowAsStr=
else ShowAsStr=1
fi
if [[ $Verbose ]]; then
echo; echo "Str: ($(grep -sc '[[:print:]]' <<< "$InputText"))"; echo "$InputText"; echo
printf "Filters: -F \"%s\" -S \"%s\" -D \"%s\" \n\n" "$FilterString" "$StartString" "$DeleteString"
declare -p FilterArr ; echo
declare -p StartArr ; echo
declare -p DeleteArr ; echo
fi
if [[ $UseSortV ]] && ! sort --help | grep -sq -o 'version-sort' ; then
if [[ $NoSortVfallback ]]; then
printf "\n Sorry, 'sort -V' is not available, you need 'jq' to run this script. \n" >&2
else UseSortV= ; fi
fi
if [[ ! $UseSortV ]] && [[ ! "$(command -v jq)" ]]; then
printf "\n Sorry, you need to install 'jq' to run this script. \n" >&2
fi
# -gt test data is fairly controllable and always using full grep avoids error fails
[[ $GTcompare ]] && GrepFull=1
# extract
if [[ $GrepFull ]]; then
# based on https://unix.stackexchange.com/a/290978/471703 and others
Nums="$(grep -sEo \
'[0-9]+([.][0-9]+)+([.][0-9]+)?+([.][0-9]+)?+([.][0-9]+)?+([-][[:alnum:]]+)?+([.][[:digit:]]+)?' <<< "$InputText" )"
else
# grep for all entries but then remove any with suffixes
Nums="$(grep -sEo \
'[0-9]+([.][0-9]+)+([.][0-9]+)?+([.][0-9]+)?+([.][0-9]+)?+([-][[:alnum:]]+)?+([.][[:digit:]]+)?' <<< "$InputText" | \
grep -v -sE '[[:alpha:]]' )"
fi
# make sure list is line seaprated
printf -v Nums "%s\n" "$Nums"
# check
Nums="$(grep -s '[[:print:]]' <<< "$Nums")"
NumsCount="$(grep -sc '[[:print:]]' <<< "$Nums")"
[[ $Verbose ]] && { echo "Nums: ($NumsCount)"; echo "$Nums"; echo ;}
if [[ $GTcompare ]] && [[ "$NumsCount" != 2 ]]; then
printf "\n ERROR: two floating point or semantic version values should be supplied" >&2
show_help >&2 ; return 1
fi
# none found, return false
[[ ! $Nums ]] && return 1
mapfile -t NumArrTemp <<< "$(tr ' ' '\n' <<< "$Nums")"
[[ $Verbose ]] && { declare -p NumArrTemp ; echo ;}
# sort unique, as required
if [[ $ShowAll ]]; then mapfile -t NumArrSorted <<< "$(printf "%s\n" "${NumArrTemp[@]}")"
else mapfile -t NumArrSorted <<< "$(printf "%s\n" "${NumArrTemp[@]}" | sort -u )"
fi
[[ $Verbose ]] && { declare -p NumArrSorted ; echo ;}
[[ $Verbose ]] && [[ $UseSortV ]] && { echo "Using SortV" ; echo ;}
# sort into order
if [[ $SortNum ]]; then
mapfile -t fvOutputArr <<< "$(printf "%s\n" "${NumArrSorted[@]}" | sort -n )"
elif [[ $UseSortV ]]; then
mapfile -t fvOutputArr <<< "$(printf "%s\n" "${NumArrSorted[@]}" | sort -V )"
else
# See https://stackoverflow.com/a/77961624/27611101 and others
mapfile -t fvOutputArr <<< "$(printf "%s\n" "${NumArrSorted[@]}" | jq -Rrn '
# read input lines as an array
[inputs]
|sort_by(
# ignore build
split("+")[0]
# extract version core and pre-release as arrays of numbers and strings
|split("-")|(.[0]|split(".")|map(tonumber? // .)) as $version_core
|(.[1:]|join("-")|split(".")|map(tonumber? // .)) as $pre_release
# sort by
|$version_core,
# pre-release versions have a lower precedence than the associated normal version
($pre_release|length)==0,
# sort by
$pre_release
)
#extract values from an array
|.[]'
)"
fi
[[ $Verbose ]] && { declare -p fvOutputArr ; echo; }
# Filters
if [[ ! $GTcompare ]]; then
if [[ $FilterString ]]; then n=0
while [[ $n -lt "${#FilterArr[@]}" ]]; do
[[ $Verbose ]] && { echo "Select: ${FilterArr[n]}"; echo ;}
NumArrTemp=(); i=0
mapfile -t NumArrTemp <<< "$(printf "%s\n" "${fvOutputArr[@]}" | grep -s "${FilterArr[n]}")"
[[ $Verbose ]] && { declare -p NumArrTemp ; echo ;}
while [[ $i -lt "${#NumArrTemp[@]}" ]]; do SelectArrTemp+=("${NumArrTemp[i]}"); ((i+=1)); done
[[ $Verbose ]] && { declare -p SelectArrTemp ; echo ;}
((n++))
done
fvOutputArr=(); i=0
while [[ $i -lt "${#SelectArrTemp[@]}" ]]; do fvOutputArr+=("${SelectArrTemp[i]}"); ((i+=1)); done
[[ $Verbose ]] && { declare -p fvOutputArr ; echo; }
fi
if [[ $StartString ]]; then n=0
while [[ $n -lt "${#StartArr[@]}" ]]; do
[[ $Verbose ]] && { echo "Starts: ${StartArr[n]}"; echo ;}
NumArrTemp=(); i=0
mapfile -t NumArrTemp <<< "$(printf "%s\n" "${fvOutputArr[@]}" | grep -sE ^"${StartArr[n]}")"
[[ $Verbose ]] && { declare -p NumArrTemp ; echo ;}
while [[ $i -lt "${#NumArrTemp[@]}" ]]; do SelectArrTemp+=("${NumArrTemp[i]}"); ((i+=1)); done
[[ $Verbose ]] && { declare -p SelectArrTemp ; echo ;}
((n++))
done
fvOutputArr=(); i=0
while [[ $i -lt "${#SelectArrTemp[@]}" ]]; do fvOutputArr+=("${SelectArrTemp[i]}"); ((i+=1)); done
[[ $Verbose ]] && { declare -p fvOutputArr ; echo; }
fi
if [[ $DeleteString ]]; then n=0
while [[ $n -lt "${#DeleteArr[@]}" ]]; do
[[ $Verbose ]] && { echo "Delete: ${DeleteArr[n]}"; echo ;}
NumArrTemp=(); i=0
while [[ $i -lt "${#fvOutputArr[@]}" ]]; do NumArrTemp+=("${fvOutputArr[i]}"); ((i+=1)); done
[[ $Verbose ]] && { declare -p NumArrTemp ; echo ;}
mapfile -t fvOutputArr <<< "$(printf "%s\n" "${NumArrTemp[@]}" | grep -sv "${DeleteArr[n]}")"
[[ $Verbose ]] && { declare -p fvOutputArr ; echo; }
((n++))
done
fi
if [[ $ShowRev ]]; then
NumArrTemp=(); i="${#fvOutputArr[@]}"
((i-=1)) # to make sure that "${fvOutputArr[0]}" gets read
while [[ $i -ge 0 ]]; do NumArrTemp+=("${fvOutputArr[i]}"); ((i-=1)); done
mapfile -t fvOutputArr <<< "$(printf "%s\n" "${NumArrTemp[@]}")"
[[ $Verbose ]] && { echo "Rev:"; declare -p fvOutputArr ; echo; }
fi
if [[ $TopMax ]]; then
# similar to ShowRev but separate in case TopMax needs reversing first
# TopShow is there to invert TopMax as the filter counts backwards from the end
NumArrTemp=(); i="${#fvOutputArr[@]}"
[[ $Verbose ]] && { echo "TopMax pre-process(1): i = $i TopMax = $TopMax TopShow = $TopShow"; echo; }
if [[ $i -gt "$TopMax" ]]; then TopShow="$((i-TopMax))"; else TopShow="$i"; fi ; ((i-=1))
[[ $TopShow -gt "$i" ]] && TopShow="0"
[[ $Verbose ]] && { echo "TopMax pre-process(2): i = $i TopMax = $TopMax TopShow = $TopShow"; echo; }
while true; do NumArrTemp+=("${fvOutputArr[i]}"); ((i-=1)); [[ $i -lt "$TopShow" ]] && break; done
[[ $Verbose ]] && { echo "TopMax post-process(1):"; echo "TopMax = $TopMax TopShow = $TopShow"; declare -p NumArrTemp ; echo ;}
mapfile -t fvOutputArr <<< "$(printf "%s\n" "${NumArrTemp[@]}")"
[[ $Verbose ]] && { echo "TopMax post-process(2):"; declare -p fvOutputArr ; echo; }
if [[ $RevMax ]]; then
NumArrTemp=(); i="${#fvOutputArr[@]}"; ((i-=1))
while [[ $i -ge 0 ]]; do NumArrTemp+=("${fvOutputArr[i]}"); ((i-=1)); done
mapfile -t fvOutputArr <<< "$(printf "%s\n" "${NumArrTemp[@]}")"
[[ $Verbose ]] && { echo "RevMax:"; declare -p fvOutputArr ; echo; }
fi
fi
fi
# output
if [[ $GTcompare ]]; then
if [[ "${NumArrTemp[0]}" == "${fvOutputArr[-1]}" ]] && [[ "${NumArrTemp[0]}" != "${NumArrTemp[1]}" ]]; then
[[ $Verbose ]] && { echo "true"; echo ;} ; return 0
else [[ $Verbose ]] && { echo "false"; echo ;} ; return 1
fi
elif [[ $ShowAsStr || $ShowAll ]] && [[ ! $ShowAsCol ]]; then
if [[ $SingleSpace ]]; then printf "%s " "${fvOutputArr[@]}"
else printf "%s " "${fvOutputArr[@]}"
fi
printf "\n"
elif [[ $ShowAsCol ]]; then
printf "%s\n" "${fvOutputArr[@]}"
elif [[ $RevMax ]]; then
echo "${fvOutputArr[0]}"
else
# then default to = ShowMax (-1 ie the last one in the array)
echo "${fvOutputArr[-1]}"
fi
if [[ $FvArrFilePath ]]; then
printf "%s\n" "${fvOutputArr[@]}" > "$FvArrFilePath"
fi
}
##
# COMPACT VERSION, suitable for embedding into other scripts, if preferred (help and annotation removed)
# # NB make sure that locale is set in the main script. See notes at start.
floatversion () {
# floatversion --options "quoted-input-string-or-text-file"
# (c) Alex Genovese - version 1.02.02 (compact) - Usage/Help/Details @ https://github.com/TuxVinyards/floatversion
local ShowAsStr= ; local ShowAsCol= ; local ShowMax= ; local ShowRev= ; local ShowAll= ; local SortNum= ; local GrepFull=
local InputText= ; local Nums= ; local NumsCount= ; local FilterString= ; local StartString= ; local DeleteString= ; local GTcompare=
local UseSortV= ; local NoSortVfallback= ; declare -a NumArrTemp ; declare -a NumArrSorted ; declare -a SelectArrTemp
declare -a FilterArr ; declare -a StartArr ; declare -a DeleteArr ; declare -ga fvOutputArr
while [[ "$1" ]] ; do
case "$1" in
-c|--col) ShowAsCol=1 ; shift ;;
-s|--space ) SingleSpace=1 ; shift ;;
-r|--rev) ShowRev=1 ; shift ;;
-a|--all) ShowAll=1 ; shift ;;
-n|--num) SortNum=1 ; shift ;;
-f|--full) GrepFull=1 ; shift ;;
-F|--filter) [[ ! $2 ]] && return 1 ; FilterString="$2" ; shift 2 ;;
-S|--start) [[ ! $2 ]] && return 1 ; StartString="$2" ; shift 2 ;;
-D|--delete) [[ ! $2 ]] && return 1 ; DeleteString="$2" ; shift 2 ;;
-M|--max) ShowMax=1 ; shift ; [[ "$1" == [1-9] || "$1" == [1-9][0-9] ]] && { TopMax="$1"; ShowMax=; shift; } ;;
-RM) ShowMax=1 ; RevMax=1 ; shift ; [[ "$1" == [1-9] || "$1" == [1-9][0-9] ]] && { TopMax="$1"; ShowMax=; shift; } ;;
-g|--gt) GTcompare=1 ; shift ;;
--sort-v) UseSortV=1 ; shift ;;
--no-svb) NoSortVfallback=1 ; shift ;;
*) if [[ "$1" == '-'* ]]; then printf "\n ERROR: '%s' not recognised \n\n" "$1" >&2 ; return 1
elif [[ $InputText ]]; then printf "\n ERROR: QUOTED Input String or Text File Name should be given only once \n\n" >&2 ; return 1
else InputText="$1" ; shift ; fi ;;
esac
done
[[ -e "$InputText" ]] && InputText="$(cat -A "$InputText")"
InputText="$(tr -cd '[:print:]' <<< "$InputText" | tr ';' ' ' | tr '$' ' ' | tr ' ' '\n' | grep -sE '[[:print:]]')"
[[ ! $InputText ]] && printf "\n ERROR: no input found. Is '-i' or '-g' the last parameter plus input the last quoted element? \n\n" >&2 && return 1
[[ $FilterString ]] && mapfile -t FilterArr <<< "$(tr ' ' '\n' <<< "$FilterString")"
[[ $StartString ]] && mapfile -t StartArr <<< "$(tr ' ' '\n' <<< "$StartString")"
[[ $DeleteString ]] && mapfile -t DeleteArr <<< "$(tr ' ' '\n' <<< "$DeleteString")"
if [[ $ShowMax ]]; then ShowAsStr= ; ShowAsCol= ; elif [[ $ShowAsCol ]]; then ShowAsStr= ; else ShowAsStr=1 ; fi
if [[ $UseSortV ]] && ! sort --help | grep -sq -o 'version-sort' ; then
if [[ $NoSortVfallback ]]; then printf "\n Sorry, 'sort -V' is not available, you need 'jq' to run this script. \n\n" >&2 ; else UseSortV= ; fi
fi
if [[ ! $UseSortV ]] && [[ ! "$(command -v jq)" ]]; then printf "\n Sorry, you need to install 'jq' to run this script. \n\n" >&2 ; fi
[[ $GTcompare ]] && GrepFull=1
if [[ $GrepFull ]]; then Nums="$(grep -sEo '[0-9]+([.][0-9]+)+([.][0-9]+)?+([.][0-9]+)?+([.][0-9]+)?+([-][[:alnum:]]+)?+([.][[:digit:]]+)?' <<< "$InputText" )"
else Nums="$(grep -sEo '[0-9]+([.][0-9]+)+([.][0-9]+)?+([.][0-9]+)?+([.][0-9]+)?' <<< "$InputText" )"; fi ; printf -v Nums "%s\n" "$Nums"
Nums="$(grep -s '[[:print:]]' <<< "$Nums")" ; NumsCount="$(grep -sc '[[:print:]]' <<< "$Nums")"
if [[ $GTcompare ]] && [[ "$NumsCount" != 2 ]]; then printf "\n ERROR: two floating point or semantic version values should be supplied \n\n" >&2 ; return 1 ; fi
[[ ! $Nums ]] && return 1
mapfile -t NumArrTemp <<< "$(tr ' ' '\n' <<< "$Nums")"
if [[ $ShowAll ]]; then mapfile -t NumArrSorted <<< "$(printf "%s\n" "${NumArrTemp[@]}")"
else mapfile -t NumArrSorted <<< "$(printf "%s\n" "${NumArrTemp[@]}" | sort -u )" ; fi
if [[ $SortNum ]]; then mapfile -t fvOutputArr <<< "$(printf "%s\n" "${NumArrSorted[@]}" | sort -n )"
else
mapfile -t fvOutputArr <<< "$(printf "%s\n" "${NumArrSorted[@]}" | jq -Rrn '
[inputs] |sort_by( split("+")[0]
|split("-")|(.[0]|split(".")|map(tonumber? // .)) as $version_core
|(.[1:]|join("-")|split(".")|map(tonumber? // .)) as $pre_release
|$version_core, ($pre_release|length)==0, $pre_release
) |.[]' )"
fi
if [[ ! $GTcompare ]]; then
if [[ $FilterString ]]; then n=0
while [[ $n -lt "${#FilterArr[@]}" ]]; do NumArrTemp=(); i=0
mapfile -t NumArrTemp <<< "$(printf "%s\n" "${fvOutputArr[@]}" | grep -s "${FilterArr[n]}")"
while [[ $i -lt "${#NumArrTemp[@]}" ]]; do SelectArrTemp+=("${NumArrTemp[i]}"); ((i+=1)); done; ((n++))
done
fvOutputArr=(); i=0 ; while [[ $i -lt "${#SelectArrTemp[@]}" ]]; do fvOutputArr+=("${SelectArrTemp[i]}"); ((i+=1)); done
fi
if [[ $StartString ]]; then n=0
while [[ $n -lt "${#StartArr[@]}" ]]; do NumArrTemp=(); i=0
mapfile -t NumArrTemp <<< "$(printf "%s\n" "${fvOutputArr[@]}" | grep -sE ^"${StartArr[n]}")"
while [[ $i -lt "${#NumArrTemp[@]}" ]]; do SelectArrTemp+=("${NumArrTemp[i]}"); ((i+=1)); done; ((n++))
done
fvOutputArr=(); i=0 ; while [[ $i -lt "${#SelectArrTemp[@]}" ]]; do fvOutputArr+=("${SelectArrTemp[i]}"); ((i+=1)); done
fi
if [[ $DeleteString ]]; then n=0
while [[ $n -lt "${#DeleteArr[@]}" ]]; do NumArrTemp=(); i=0
while [[ $i -lt "${#fvOutputArr[@]}" ]]; do NumArrTemp+=("${fvOutputArr[i]}"); ((i+=1)); done
mapfile -t fvOutputArr <<< "$(printf "%s\n" "${NumArrTemp[@]}" | grep -sv "${DeleteArr[n]}")" ; ((n++))
done
fi
if [[ $ShowRev ]]; then NumArrTemp=(); i="${#fvOutputArr[@]}"; ((i-=1))
while [[ $i -ge 0 ]]; do NumArrTemp+=("${fvOutputArr[i]}"); ((i-=1)); done
mapfile -t fvOutputArr <<< "$(printf "%s\n" "${NumArrTemp[@]}")"
fi
if [[ $TopMax ]]; then NumArrTemp=(); i="${#fvOutputArr[@]}"
if [[ $i -gt "$TopMax" ]]; then TopShow="$((i-TopMax))"; else TopShow="$i"; fi ; ((i-=1)) ; [[ $TopShow -gt "$i" ]] && TopShow="0"
while true; do NumArrTemp+=("${fvOutputArr[i]}"); ((i-=1)); [[ $i -lt "$TopShow" ]] && break; done
mapfile -t fvOutputArr <<< "$(printf "%s\n" "${NumArrTemp[@]}")"
if [[ $RevMax ]]; then NumArrTemp=(); i="${#fvOutputArr[@]}"; ((i-=1))
while [[ $i -ge 0 ]]; do NumArrTemp+=("${fvOutputArr[i]}"); ((i-=1)); done
mapfile -t fvOutputArr <<< "$(printf "%s\n" "${NumArrTemp[@]}")"
fi
fi
fi
if [[ $GTcompare ]]; then
if [[ "${NumArrTemp[0]}" == "${fvOutputArr[-1]}" ]] && [[ "${NumArrTemp[0]}" != "${NumArrTemp[1]}" ]]; then return 0 ; else return 1 ; fi
elif [[ $ShowAsStr || $ShowAll ]] && [[ ! $ShowAsCol ]]; then
if [[ $SingleSpace ]]; then printf "%s " "${fvOutputArr[@]}"; else printf "%s " "${fvOutputArr[@]}"; fi
elif [[ $ShowAsCol ]]; then printf "%s\n" "${fvOutputArr[@]}"
elif [[ $RevMax ]]; then echo "${fvOutputArr[0]}"
else echo "${fvOutputArr[-1]}"
fi
}
##
# script call, developer option
if [[ $1 == "-C" ]] || [[ $1 == "--compact" ]]; then shift ; floatversion "$@"
elif [[ $CompactVersion ]]; then floatversion "$@"
else float_version_from_string "$@"
fi
# https://code.visualstudio.com/
# vim:tabstop=2:shiftwidth=2:expandtab