bash remove element from array and bash remove item from array usually mean
either “drop this value”, “drop the first/last slot”, bash array remove duplicates,
or “everything in A that is not listed in B” (the original title of this
page). Pick one job; mixing them is how scripts grow grep pipes that break on spaces.
If your data started as a string, split first with
bash split string into array.
Snippets below were run with Bash 5.2.37 on Ubuntu 25.04 (kernel 6.14.0-37-generic).
bash remove item from array (filter by value)
Build a new array and skip the value you do not want—safe with spaces and glob characters because the array stays quoted:
array1=(a b c d)
remove=b
filtered=()
for item in "${array1[@]}"; do
[[ $item == "$remove" ]] && continue
filtered+=("$item")
done
printf '%s ' "${filtered[@]}"
echoa c dThat is the usual answer to bash remove from array / remove element from array bash when you only remove one known token.
bash remove first element from array (or tail by slice)
Slices are the fast path for “drop head or tail” without scanning:
nums=(10 20 30 40)
rest=("${nums[@]:1}") # drop first
echo "${rest[@]}"20 30 40Drop the last element on Bash 4.3+:
nums=(10 20 30)
unset 'nums[-1]'
echo "${nums[@]}"10 20bash array remove duplicates (uniq, or order-preserving map)
Sorted input, order not important:
vals=(b a b c a)
printf '%s\n' "${vals[@]}" | sort -ua
b
cbash remove duplicates from array while keeping first-seen order needs an associative array (Bash 4+):
vals=(a b a c b)
declare -A seen=()
deduped=()
for v in "${vals[@]}"; do
[[ -n ${seen[$v]+isset} ]] && continue
seen[$v]=1
deduped+=("$v")
done
printf '%s ' "${deduped[@]}"
echoa b cDelete elements of one array from another (set difference A \ B)
Mark everything in B, walk A, skip hits—O(n) and robust for arbitrary strings
(unlike ${a[@]/x/} tricks that leave empty slots or partial substring matches):
A=(a b c d)
B=(b e)
declare -A drop=()
for x in "${B[@]}"; do drop[$x]=1; done
out=()
for x in "${A[@]}"; do
[[ -n ${drop[$x]+isset} ]] && continue
out+=("$x")
done
printf '%s ' "${out[@]}"
echoa c dThat is the clean bash remove item from list pattern when the “list” to remove lives in a second array.
Why not ${array[@]/pattern/} for removal?
${arr[@]/b/} substitutes substring matches inside every element and can leave
empty entries ("") instead of removing a slot. It also treats patterns as
substrings, not “whole cell equals b”. Prefer explicit loops or an associative map.
comm / grep shortcuts (when data is simple)
If every token is a single word with no spaces, sorted comm -23 can print
A \ B:
A=(a b c d)
B=(b e)
comm -23 <(printf '%s\n' "${A[@]}" | sort) <(printf '%s\n' "${B[@]}" | sort) | paste -sd' ' -a c dKeep the map version when elements can contain spaces or you care about original order.
Related
- bash concatenate strings when building lines from arrays.
- beginner Bash arguments for passing array-like data into scripts.
- prepend to arrays and positional parameters (
unshiftpatterns in Bash) when you are reshaping lists at the head as well as the tail.
Summary
Use a quoted loop for bash remove element from array by value, "${arr[@]:1}"
or unset 'arr[-1]' for bash remove first element from array (or trimming the
tail), sort -u or an declare -A pass for bash array remove duplicates /
bash remove duplicates from array, and an associative “drop set” for delete
elements of one array from another. Avoid ${array[@]/x/} unless you truly want
substring substitution with possible empty cells; prefer explicit tests for bash
remove item from list clarity.

