-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patharray_remove
More file actions
executable file
·145 lines (140 loc) · 5.38 KB
/
array_remove
File metadata and controls
executable file
·145 lines (140 loc) · 5.38 KB
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
#!/usr/bin/env bash
##region########################################### HELP & VERSION ###########################################
_show_help() {
# -f, --first, --forward[s]: Search from the beginning of the list. Mutually exclusive with -l. Default.
# -l, --last, -b, --backward[s]: Search from the end of the list. Mutually exclusive with -f.
cat << __EOF__
Removes the specified values from the list.
Usage: $0 [-sar] [--] VALUE ENTRY1 ENTRY2...
or: $0 --value VALUE [-sar] [--] ENTRY1 ENTRY2...
or: $0 --index VALUE [-sar] [--] ENTRY1 ENTRY2...
or: $0 --index [-sar] [--] VALUE ENTRY1 ENTRY2...
or: $0 [--last|first] [--] VALUE ENTRY1 ENTRY2...
or: $0 --help
or: $0 --version
Options:
-h, --help: Shows this help text.
--version: Shows version info.
-i, --index[-at/_at], --at[-index/_index] [VALUE]: The index of the value to remove. If value wasn't assigned by a preceding option & the following token is an integer, that token will be used as 'VALUE'. If value wasn't assigned by a preceding option & the following token is not an integer, value will be assigned by a later '--value' option, the first argument after a terminating --, or the first argument to not match a parameter nor follow a named parameter.
-v, --value VALUE: The value to remove. Can be an empty string.
-r, --regex: Treat 'VALUE' as an extended regex.
-I, --invert: Instead of searching for matching values, searches for non-matching values. Mainly useful for filtering a list into matching and non-matching members.
-a, --all: Remove all matching values.
-d, --delim, --delimiter DELIMITER: A string literal to be placed in between each element in the returned list & after the last element. If the input may contain spaces and/or newlines, use a value like \$'\\003' (ASCII ETX) & mapfile to break the output back into an array.
-c, --count [DELIMITER]: Print the number of elements in the returned list before the list itself. Separated from the first element by DELIMITER. If the token after the flag doesn't match any options, it will be used as the count delimiter. Defaults to a single newline.
--: Stop processing arguments. If 'VALUE' isn't assigned to yet, the next token will be used.
Exit Status:
0 if found, 1 if not found, 255 for undefined execution error.
__EOF__
}
_show_version() {
cat << __EOF__
$0 3.0.0
Copyright (C) 2025 Justin Morris
__EOF__
}
##endregion######################################## HELP & VERSION ###########################################
set -e
declare -r numericMatcher='^[-+]?[[:digit:]]+$'
declare fInvert='false'
declare fAll='false'
declare fAt='false'
declare fRegex='false'
declare fCount='false'
# declare countDelim=
declare delim=$'\n' # declare delim=$'\003'
shopt -s extglob globasciiranges
# TODO: Forwards & Backwards options?
# while (($# > 0)); do
while true; do
case "$1" in
-c | --count) declare -r fCount='true'; shift; continue;;
-d | --delim | --delimiter) shift; declare -r delim="$1";;
-s | --single | -o | --one) declare -r fAll='false';;
-a | --all) declare -r fAll='true';;
-I | --invert) declare -r fInvert='true';;
-r | --regex) declare -r fRegex='true';;
-i | --index | --index[-_]at | --at | --at[-_]index)
declare -r fAt='true'
if ! [ -v toRemove ] && [[ "$2" =~ $numericMatcher ]]; then
shift
declare toRemove="$1"
fi
;;
# TODO: Warn if value overwritten?
-v | --value) shift; declare toRemove="$1";;
-h | --help) _show_help; exit 0;;
--version) _show_version; exit 0;;
*)
if eval "$fCount" && ! [ -v countDelim ]; then
declare -r countDelim="$1"
shift
continue
fi
if ! [ -v toRemove ]; then
declare toRemove="$1"
if ! shift; then
echo "No array elements" 1>&2
exit 1
fi
fi
break
;;
esac
shift
if eval "$fCount" && ! [ -v countDelim ]; then declare -r countDelim=$'\n'; fi
done
if ! [ -v toRemove ]; then
echo "toRemove Undefined" 1>&2
exit 1
fi
if eval "$fCount" && ! [ -v countDelim ]; then
echo "countDelim Undefined" 1>&2
exit 1
fi
declare -r toRemove="$toRemove" fAll fAt delim fRegex fInvert
declare -a result=()
if eval "$fAt"; then
# TODO: account for octal & such https://www.gnu.org/software/bash/manual/bash.html#Shell-Arithmetic
if ! [[ "$toRemove" =~ $numericMatcher ]]; then
echo "Cannot remove non-numeric index $toRemove" 1>&2
exit 1
else
declare -i toRemove # If octal or whatever, fixes it for upcoming error messages
if ((toRemove >= $#)); then
echo "Cannot remove index $toRemove that exceeds array length of $#" 1>&2
exit 1
elif ((toRemove < 0 && toRemove * 1 >= $#)); then
echo "Cannot remove negative index $toRemove that exceeds array length of $#" 1>&2
exit 1
fi
fi
result=("$@")
unset "result[$toRemove]"
# result=("${result[@]}") # Fixes indices
else
function _regexMatch() { if eval "$fInvert"; then ! [[ "$1" =~ $toRemove ]] && return 0 || return 1; else [[ "$1" =~ $toRemove ]] && return 0 || return 1; fi }
function _literalMatch() { if eval "$fInvert"; then ! [ "$1" = "$toRemove" ] && return 0 || return 1; else [ "$1" = "$toRemove" ] && return 0 || return 1; fi }
while (($# > 0)); do
if (eval "$fRegex" && _regexMatch "$1") ||
(! eval "$fRegex" && _literalMatch "$1"); then
if eval "$fAll"; then
shift
continue
fi
if shift; then
result+=("$@")
fi
break
fi
result+=("$1")
shift
done
fi
IFS="$delim"
if eval "$fCount"; then
echo -nE "${#result[*]}$countDelim${result[*]}$delim"
else
echo -nE "${result[*]}$delim"
fi
exit