如何从bash中的字符串/数组创建唯一元素数组?

Mic*_*ant 9 array string uniq patterns

如果我有一个字符串“1 2 3 2 1” - 或一个数组 [1,2,3,2,1] - 我如何选择唯一值,即

"1 2 3 2 1" produces "1 2 3" 
Run Code Online (Sandbox Code Playgroud)

或者

[1,2,3,2,1] produces [1,2,3]
Run Code Online (Sandbox Code Playgroud)

类似于 uniq 但 uniq 似乎适用于整行,而不是一行内的模式......

jim*_*mij 11

如果您使用的是 zsh:

$ array=(1 2 3 2 1)
$ echo ${(u)array[@]}
1 2 3
Run Code Online (Sandbox Code Playgroud)

或(如果KSH_ARRAYS未设置选项)甚至

$ echo ${(u)array}
1 2 3
Run Code Online (Sandbox Code Playgroud)


iru*_*var 5

使用 GNU awk(这也保留原始顺序)

printf '%s\n' "1 2 3 2 1" | awk -v RS='[[:space:]]+' '!a[$0]++{printf "%s%s", $0, RT}'
1 2 3 
Run Code Online (Sandbox Code Playgroud)

readbash阵列

read -ra arr<<<$(printf '%s\n' "1 2 3 2 1" |
 awk -v RS='[[:space:]]+' '!a[$0]++{printf "%s%s", $0, RT}')
printf "%s\n"  "${arr[@]}"
1
2
3
Run Code Online (Sandbox Code Playgroud)


Sté*_*las 5

对于具有任意值的数组,这是相当棘手的,bash因为它没有内置的运算符。

bash但是碰巧不支持在其变量中存储 NUL 字符,因此您可以利用它将其传递给其他命令:

相当于 的zsh

new_array=("${(@u}array}")
Run Code Online (Sandbox Code Playgroud)

在最近的 GNU 系统上,可能是:

eval "new_array=($(
  printf "%s\0" "${array[@]}" |
    LC_ALL=C sort -zu |
    xargs -r0 bash -c 'printf "%q\n" "$@"' sh
  ))"
Run Code Online (Sandbox Code Playgroud)

或者,使用最新版本的bash,并假设所有数组元素都不为空,您可以使用关联数组:

unset hash
typeset -A hash
for i in "${array[@]}"; do
  hash[$i]=
done
new_array=("${!hash[@]}")
Run Code Online (Sandbox Code Playgroud)

使用 bash 4.4 及更新版本和 GNU sort

readarray -td '' new_array < <(
  printf '%s\0' "${array[@]}" | LC_ALL=C sort -zu)
Run Code Online (Sandbox Code Playgroud)

在这些不同的解决方案中,元素的顺序不会相同。

tcsh

set -f new_array = ($array:q)
Run Code Online (Sandbox Code Playgroud)

将保留第一个元素 ( a b a=> a b),例如zsh(u)扩展标志。

set -l new_array = ($array:q)
Run Code Online (Sandbox Code Playgroud)

将保留最后一个 ( a b a=> b a)。然而,它们从数组中删除空元素。