Array intersection in Bash
The elements of list 1 are used as regular expression looked up in list2 (expressed as string: ${list2[*]} ):
list1=( 1 2 3 4 6 7 8 9 10 11 12)
list2=( 1 2 3 5 6 8 9 11 )
l2=" ${list2[*]} " # add framing blanks
for item in ${list1[@]}; do
if [[ $l2 =~ " $item " ]] ; then # use $item as regexp
result+=($item)
fi
done
echo ${result[@]}
The result is
1 2 3 6 8 9 11
Merging two arrays in Bash
Since Bash supports sparse arrays, it's better to iterate over the array than to use an index based on the size.
a=(0 1); b=(2 3)
i=0
for z in ${a[@]}
do
for y in ${b[@]}
do
c[i++]="$z:$y"
done
done
declare -p c # dump the array
Outputs:
declare -a c='([0]="0:2" [1]="0:3" [2]="1:2" [3]="1:3")'
Bash - iterate over a union of two (disjoint) arrays
Just put one after the other:
for i in "${rpool_fs[@]}" "${shares_fs[@]}"
do
echo $i
done
Bash: How do I combine two arrays into a third array?
From The Advanced Bash Scripting Guide example 27-10, with a correction:
declare -a array1=( zero1 one1 two1 )
declare -a array2=( [0]=zero2 [2]=two2 [3]=three2 )
dest=( "${array1[@]}" "${array2[@]}" )
Thus, for my case, it's:
array3=( "${array1[@]}" "${array2[@]}" )
Find items common between two Bash arrays
You can use comm
with process substitution instead of looping:
mapfile -t new_number1 < <(comm -12 <(printf '%s\n' "${number1[@]}" | sort) <(printf '%s\n' $range_f | sort))
mapfile -t new_number2 < <(comm -12 <(printf '%s\n' "${number2[@]}" | sort) <(printf '%s\n' $range_f | sort))
mapfile -t name
reads from the nested process substitution into the named arrayprintf ... | sort
pair provides the sorted input streams for commcomm -12
emits the items common to the two streams
Intersection of two lists in Bash
comm -12 <(ls 1) <(ls 2)
Compare/Difference of two arrays in Bash
If you strictly want Array1 - Array2
, then
Array1=( "key1" "key2" "key3" "key4" "key5" "key6" "key7" "key8" "key9" "key10" )
Array2=( "key1" "key2" "key3" "key4" "key5" "key6" )
Array3=()
for i in "${Array1[@]}"; do
skip=
for j in "${Array2[@]}"; do
[[ $i == $j ]] && { skip=1; break; }
done
[[ -n $skip ]] || Array3+=("$i")
done
declare -p Array3
Runtime might be improved with associative arrays, but I personally wouldn't bother. If you're manipulating enough data for that to matter, shell is the wrong tool.
For a symmetric difference like Dennis's answer, existing tools like comm
work, as long as we massage the input and output a bit (since they work on line-based files, not shell variables).
Here, we tell the shell to use newlines to join the array into a single string, and discard tabs when reading lines from comm
back into an array.
$ oldIFS=$IFS IFS=$'\n\t'
$ Array3=($(comm -3 <(echo "${Array1[*]}") <(echo "${Array2[*]}")))
comm: file 1 is not in sorted order
$ IFS=$oldIFS
$ declare -p Array3
declare -a Array3='([0]="key7" [1]="key8" [2]="key9" [3]="key10")'
It complains because, by lexographical sorting, key1 < … < key9 > key10
. But since both input arrays are sorted similarly, it's fine to ignore that warning. You can use --nocheck-order
to get rid of the warning, or add a | sort -u
inside the <(…)
process substitution if you can't guarantee order&uniqueness of the input arrays.
How can I join elements of an array in Bash?
A 100% pure Bash function that supports multi-character delimiters is:
function join_by {
local d=${1-} f=${2-}
if shift 2; then
printf %s "$f" "${@/#/$d}"
fi
}
For example,
join_by , a b c #a,b,c
join_by ' , ' a b c #a , b , c
join_by ')|(' a b c #a)|(b)|(c
join_by ' %s ' a b c #a %s b %s c
join_by $'\n' a b c #a<newline>b<newline>c
join_by - a b c #a-b-c
join_by '\' a b c #a\b\c
join_by '-n' '-e' '-E' '-n' #-e-n-E-n-n
join_by , #
join_by , a #a
The code above is based on the ideas by @gniourf_gniourf, @AdamKatz, @MattCowell, and @x-yuri. It works with options errexit
(set -e
) and nounset
(set -u
).
Alternatively, a simpler function that supports only a single character delimiter, would be:
function join_by { local IFS="$1"; shift; echo "$*"; }
For example,
join_by , a "b c" d #a,b c,d
join_by / var local tmp #var/local/tmp
join_by , "${FOO[@]}" #a,b,c
This solution is based on Pascal Pilz's original suggestion.
A detailed explanation of the solutions previously proposed here can be found in "How to join() array elements in a bash script", an article by meleu at dev.to.
Related Topics
Perl Script to Capture Stderr and Stdout of Command Executed in Back-Quotes
Linux Shell Scripting: How to Remove Final Numbers in a Word List File
How to Generate Multiple Ssh Public Key and Configure Those on Windows Machine from Gitbash
How to Efficiently Get 10% of Random Lines Out of The Large File in Linux
How to Decide How Much Stack I Can Use After a Call to Pthread_Attr_Setstacksize
Required Alignment of .Text Versus .Data
Restart Service from Cgi Script
Run a Script When a New Veth Interface Is Added
Rpm Spec to Require Specific Rhel Release
Linux: Get a Script to Be Able to Ask The User for a File Name Then Open That File
Code for Wait_Event_Interruptible