blob: 39d9e453c8d49573a3b705444fce7065ae1ca589 (
plain) (
blame)
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
|
# Function to manage contents of PATH variable within the current shell
path() {
# Figure out command being called
local pathcmd
if (($#)) ; then
pathcmd=$1
shift
else
pathcmd=list
fi
# Switch between commands
case $pathcmd in
# Print help output (also done if command not found)
help|h|-h|--help|-\?)
while IFS= read -r line ; do
printf '%s\n' "$line"
done <<EOF
$FUNCNAME: Manage contents of PATH variable
USAGE:
$FUNCNAME h[elp]
Print this help message (also done if command not found)
$FUNCNAME l[ist]
Print the current directories in PATH, one per line (default command)
$FUNCNAME i[nsert] DIR
Add a directory to the front of PATH, checking for existence and uniqueness
$FUNCNAME a[ppend] DIR
Add a directory to the end of PATH, checking for existence and uniqueness
$FUNCNAME r[emove] DIR
Remove all instances of a directory from PATH
INTERNALS:
$FUNCNAME s[et] [DIR1 [DIR2...]]
Set the PATH to the given directories without checking existence or uniqueness
$FUNCNAME c[heck] DIR
Return whether DIR is a component of PATH
EOF
;;
# Print the current contents of the path
list|l)
local -a patharr
IFS=: read -a patharr < <(printf '%s\n' "$PATH")
if ((${#patharr[@]})) ; then
printf '%s\n' "${patharr[@]}"
fi
;;
# Add a directory to the front of PATH, checking for existence and uniqueness
insert|i)
local -a patharr
IFS=: read -a patharr < <(printf '%s\n' "$PATH")
local dirname
dirname=$1
[[ $dirname == / ]] || dirname=${dirname%/}
if [[ -z $dirname ]] ; then
printf 'bash: %s: need a directory path to insert\n' \
"$FUNCNAME" >&2
return 1
fi
if [[ ! -d $dirname ]] ; then
printf 'bash: %s: %s not a directory\n' \
"$FUNCNAME" "$dirname" >&2
return 1
fi
if [[ $dirname == *:* ]] ; then
printf 'bash: %s: Cannot add insert directory %s with colon in name\n' \
"$FUNCNAME" "$dirname" >&2
return 1
fi
if path check "$dirname" ; then
printf 'bash: %s: %s already in PATH\n' \
"$FUNCNAME" "$dirname" >&2
return 1
fi
patharr=("$dirname" "${patharr[@]}")
path set "${patharr[@]}"
;;
# Add a directory to the end of PATH, checking for existence and uniqueness
append|add|a)
local -a patharr
IFS=: read -a patharr < <(printf '%s\n' "$PATH")
local dirname
dirname=$1
[[ $dirname == / ]] || dirname=${dirname%/}
if [[ -z $dirname ]] ; then
printf 'bash: %s: need a directory path to append\n' \
"$FUNCNAME" >&2
return 1
fi
if [[ ! -d $dirname ]] ; then
printf 'bash: %s: %s not a directory\n' \
"$FUNCNAME" "$dirname" >&2
return 1
fi
if [[ $dirname == *:* ]] ; then
printf 'bash: %s: Cannot append directory %s with colon in name\n' \
"$FUNCNAME" "$dirname" >&2
return 1
fi
if path check "$dirname" ; then
printf 'bash: %s: %s already in PATH\n' \
"$FUNCNAME" "$dirname" >&2
return 1
fi
patharr[${#patharr[@]}]=$dirname
path set "${patharr[@]}"
;;
# Remove all instances of a directory from PATH
remove|rm|r)
local -a patharr
IFS=: read -a patharr < <(printf '%s\n' "$PATH")
local dirname
dirname=$1
[[ $dirname == / ]] || dirname=${dirname%/}
if [[ -z $dirname ]] ; then
printf 'bash: %s: need a directory path to remove\n' \
"$FUNCNAME" >&2
return 1
fi
if ! path check "$dirname" ; then
printf 'bash: %s: %s not in PATH\n' \
"$FUNCNAME" "$dirname" >&2
return 1
fi
local -a newpatharr
local part
for part in "${patharr[@]}" ; do
[[ $dirname == "$part" ]] && continue
newpatharr[${#newpatharr[@]}]=$part
done
path set "${newpatharr[@]}"
;;
# Set the PATH to the given directories without checking existence or uniqueness
set|s)
local -a newpatharr
local dirname
for dirname ; do
newpatharr[${#newpatharr[@]}]=$dirname
done
PATH=$(IFS=: ; printf '%s' "${newpatharr[*]}")
;;
# Return whether directory is a component of PATH
check|c)
local -a patharr
IFS=: read -a patharr < <(printf '%s\n' "$PATH")
local dirname
dirname=$1
[[ $dirname == / ]] || dirname=${dirname%/}
if [[ -z $dirname ]] ; then
printf 'bash: %s: need a directory path to check\n' \
"$FUNCNAME" >&2
return 1
fi
local part
for part in "${patharr[@]}" ; do
if [[ $dirname == "$part" ]] ; then
return 0
fi
done
return 1
;;
# Unknown command
*)
printf 'bash: %s: Unknown command %s\n' \
"$FUNCNAME" "$pathcmd" >&2
path help >&2
return 1
;;
esac
}
# Completion for path
_path() {
# What to do depends on which word we're completing
if ((COMP_CWORD == 1)) ; then
# Complete operation as first word
local cmd
for cmd in help list insert append remove set check ; do
[[ $cmd == "${COMP_WORDS[COMP_CWORD]}"* ]] || continue
COMPREPLY[${#COMPREPLY[@]}]=$cmd
done
# Complete with either directories or $PATH entries as all other words
else
case ${COMP_WORDS[1]} in
# Complete with a directory
insert|i|append|add|a|check|c|set|s)
local dirname
while IFS= read -d '' -r dirname ; do
COMPREPLY[${#COMPREPLY[@]}]=$dirname
done < <(
# Set options to glob correctly
shopt -s dotglob nullglob
# Collect directory names, strip trailing slash
local -a dirnames
dirnames=("${COMP_WORDS[COMP_CWORD]}"*/)
dirnames=("${dirnames[@]%/}")
# Bail if no results to prevent empty output
((${#dirnames[@]})) || exit 1
# Print results, quoted and null-delimited
printf '%q\0' "${dirnames[@]}"
)
;;
# Complete with directories from PATH
remove|rm|r)
local -a promptarr
IFS=: read -d '' -a promptarr < <(printf '%s\0' "$PATH")
local part
for part in "${promptarr[@]}" ; do
[[ $part == "${COMP_WORDS[COMP_CWORD]}"* ]] \
|| continue
COMPREPLY[${#COMPREPLY[@]}]=$(printf '%q\0' "$part")
done
;;
# No completion
*)
return 1
;;
esac
fi
}
complete -F _path path
|