Reputation: 49846
I'm filtering PATH
variables, such that certain elements are deleted (in the example below, it's elements containing the string x86
; in practice I'm looking for the string site-packages
):
$ echo $(IFS=:;arr=($PATH);echo "${arr[*]//*x86*}")
/usr/local/bin:/usr/bin:/cygdrive/c/Program Files/Common Files/Microsoft Shared/Windows Live::/cygdrive/c/Program Files/Lenovo Fingerprint Reader:::/cygdrive/c/Program Files/Intel/iCLS Client:/cygdrive/c/Windows/system32:/cygdrive/c/Windows:/cygdrive/c/Windows/System32/Wbem:/cygdrive/c/Windows/System32/WindowsPowerShell/v1.0:/cygdrive/c/Program Files/Intel/Intel(R) Management Engine Components/DAL:/cygdrive/c/Program Files/Intel/Intel(R) Management Engine Components/IPT:::::/cygdrive/c/Program Files/Intel/WiFi/bin:/cygdrive/c/Program Files/Common Files/Intel/WirelessCommon:/cygdrive/c/Program Files/Common Files/Lenovo:::/cygdrive/c/SWTOOLS/ReadyApps:::::/usr/lib/lapack
This works pretty well, except that all of the elements which have been zeroed out are still, there, but empty. I'd like to end up with those elements eliminated, and I don't want to use anything other than bash to do it (I know I can use tr
, but for portability reasons I would strongly prefer a bash-only solution).
Here's the tr-based solution:
echo $(IFS=:;arr=($PATH);echo "${arr[*]//*x86*}" | tr -s :)
Update: I'm using arrays because I want to be robust in the face of spaces (or anything else other than colons) in the path elements.
Upvotes: 2
Views: 2210
Reputation: 157
A variation from the examples above, which doesn't require an additional subshell, preserves spaces in PATH
and eliminates path separators along with its matches:
IFS="$IFS"; IFS=:
arr=($PATH)
"${arr[*]//*local*?(:|\/)/$'\b'}" &>/dev/null
printf "${_#*:}"
# OR: var="${_#*:}"
IFS="$_IFS"
It splits PATH
at colons into array arr
and expands it to string; then all paths between *...*
, that end either with a colon :
(Windows path separator), or slash /
(last path entry), will be replaced with a backspace, deleting the path separator for the match. In case the first path entry matches, the remnant leading colon is removed from the result by ${_#*:}
.
If used in a method, storing the result in tmp
isn't required and echo "$_"
should suffice.
Upvotes: 0
Reputation: 23364
This should work with bash assuming PATH
constituents do not contain spaces, so definitely more fragile than the other solutions. The empty array elements are discarded at the point of arr2
assignment
echo $(IFS=:;arr=($PATH);unset IFS;arr2=(${arr[@]//*x86*});IFS=:;echo "${arr2[*]}")
Upvotes: 0
Reputation: 531345
This doesn't require an explicit loop, but might be a bit fragile. It uses a backspace to "unwrite" the colon preceding a directory to remove, and it requires special handling if the first or last directory in PATH
is removed.
echo $(IFS=:;
arr=($PATH);
# When finally echoed, any \b character will remove
# the preceding colon from the output.
new="${arr[*]//*x86*/$'\b'}";
# Remove :\b if last directory was removed
new=${new%:$'\b'};
# Remove \b: if first directory was removed
echo "${new#$'\b':}")
Upvotes: 2
Reputation: 49846
Here's a version which builds up a contiguous array using a loop:
$ echo $(IFS=:;arr=($PATH);sqarr="${arr[*]//*x86*}";declare -a finalarr; for item in $sqarr; do [[ $item ]] && finalarr+=("$item"); done; echo "${finalarr[*]}")
/usr/local/bin:/usr/bin:/cygdrive/c/Program Files/Common Files/Microsoft Shared/Windows Live:/cygdrive/c/Program Files/Lenovo Fingerprint Reader:/cygdrive/c/Program Files/Intel/iCLS Client:/cygdrive/c/Windows/system32:/cygdrive/c/Windows:/cygdrive/c/Windows/System32/Wbem:/cygdrive/c/Windows/System32/WindowsPowerShell/v1.0:/cygdrive/c/Program Files/Intel/Intel(R) Management Engine Components/DAL:/cygdrive/c/Program Files/Intel/Intel(R) Management Engine Components/IPT:/cygdrive/c/Program Files/Intel/WiFi/bin:/cygdrive/c/Program Files/Common Files/Intel/WirelessCommon:/cygdrive/c/Program Files/Common Files/Lenovo:/cygdrive/c/SWTOOLS/ReadyApps:/usr/lib/lapack
Across multiple lines:
$(
IFS=:
arr=($PATH)
sqarr="${arr[*]//*x86*}"
declare -a finalarr
for item in $sqarr; do
[[ $item ]] && finalarr+=("$item")
done
echo "${finalarr[*]}"
)
Upvotes: 0
Reputation: 246867
You'll have to be more explicit about it:
PATH=$(
IFS=:
new=()
for p in $PATH; do
[[ $p != *x86* ]] && new+=("$p")
done
echo "${new[*]}"
)
It's more verbose, but correct and bash-only as requested
Upvotes: 3