Если вы строго хотите Array1 - Array2
, то
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
Время выполнения может быть улучшено с помощью ассоциативных массивов, но я лично не стал бы беспокоиться. Если вы манипулируете достаточным количеством данных, чтобы это имело значение, shell - неправильный инструмент.
Для симметричной разницы, такой как ответ Денниса, работают такие инструменты, как comm
, пока мы немного помассируем ввод и вывод (поскольку они работают с строковыми файлами, а не с переменными оболочки) .
Здесь мы говорим оболочке использовать новые строки для объединения массива в одну строку и отбрасывать вкладки при чтении строк из comm
обратно в массив.
$ 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")'
Жалуется, потому что, путем лексографической сортировки, key1 < … < key9 > key10
. Но поскольку оба входных массива отсортированы одинаково, это предупреждение можно игнорировать. Вы можете использовать --nocheck-order
, чтобы избавиться от предупреждения, или добавить | sort -u
в подстановку процесса <(…)
, если не можете гарантировать порядок и уникальность входных массивов.