I will be short, what i have is
array=( one.a two.b tree.c four.b five_b_abc)
I want this
array=( two.b four.b five_b_abc )
from here i found this
# replace any array item matching "b*" with "foo"
array=( foo bar baz )
array=( "${array[@]/%b*/foo}" )
echo "${orig[@]}"$'\n'"${array[@]}"
how ever this does not work
array2=( ${array[@]//%^.p/})
result array2=array
this deletes all with p
array2=(${array[@]/*p*/})
result array2=( one.a tree.c )
I need an idea how to do add ^p (all accept p), and get my solution
array2=(${array[@]/*^p*/}
Its a rather large array about 10k elements where i need to do this i need it to be as fast as possible with data so please no loop solutions.
Edit: added timing comparisons (at end) and got rid of the tr
It is possible to replace the content of array elements using bash Parameter expansion, ie. ${var[@]....}
but you cannot actually delete the elements. The best you can get with parameter expansion is to make null ("") those elements you do not want.
Instead, you can use printf
and sed
, and IFS
. This has the advantabe of allowing you to use full regular expression syntax (not just the shell globbing expressions)... and it is much faster than using a loop...
This example leaves array elements which contain c
Note: This method caters for spaces in data. This is achieved via IFS=\n
IFS=$'\n'; a=($(printf '%s\n' "${a[@]}" |sed '/c/!d'))
Here it is again with before/after dumps:
#!/bin/bash
a=(one.ac two.b tree.c four.b "five b abcdefg" )
echo "======== Original array ===="
printf '%s\n' "${a[@]}"
echo "======== Array containing only the matched elements 'c' ===="
IFS=$'\n'; a=($(printf '%s\n' "${a[@]}" |sed '/c/!d'))
printf '%s\n' "${a[@]}"
echo "========"
Output:
======== Original array ====
one.ac
two.b
tree.c
four.b
five b abcdefg
======== Array containing only the matched elements 'c' ====
one.ac
tree.c
five b abcdefg
========
For general reference: Testing an array containing 10k elements. selecting 5k:
a=( a\ \ \ \ b{0..9999} )
The printf method took: 0m0.226s
(results in sequential index values)
The first loop method: 0m4.007s
(it leaves gaps in index values)
The second loop method: 0m7.862s
(results in sequential index values)
printf method:
IFS=$'\n'; a=($(printf '%s\n' "${a[@]}" |sed '/.*[5-9]...$/!d'))
1st loop method:
iz=${#a[@]}; j=0
for ((i=0; i<iz; i++)) ;do
[[ ! "${a[i]}" =~ .*[5-9]...$ ]] && unset a[$i]
done
2nd loop method:
iz=${#a[@]}; j=0
for ((i=0; i<iz; i++)) ;do
if [[ ! "${a[i]}" =~ .*[5-9]...$ ]] ;then
unset a[$i]
else
a[$j]="${a[i]}=$i=$j"; ((j!=i)) && unset a[$i]; ((j+=1));
fi
done
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With