我如何从Bash中的数组获得唯一值?

我有几乎和这里一样的问题。

我有一个数组,其中包含一个aa ab aa ac aa ad等。现在我想从这个数组中select所有独特的元素。 以为,这将是简单的sort | uniq sort | uniqsort -u如他们在其他问题中提到的,但在数组中没有任何改变…代码是:

 echo `echo "${ids[@]}" | sort | uniq` 

我究竟做错了什么?

有点哈克,但这应该做到这一点:

 echo "${ids[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' ' 

要将sorting后的唯一结果保存回数组,请进行数组赋值 :

 sorted_unique_ids=($(echo "${ids[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' ')) 

如果你的shell支持herestrings ( bash应该),你可以通过修改echo进程来节省一个echo进程:

 tr ' ' '\n' <<< "${ids[@]}" | sort -u | tr '\n' ' ' 

input:

 ids=(aa ab aa ac aa ad) 

输出:

 aa ab ac ad 

说明:

  • "${ids[@]}" – 用于处理shell数组的语法,不pipe是用作echo还是herestring的一部分。 @部分的意思是“数组中的所有元素”
  • tr ' ' '\n' – 将所有空格转换为换行符。 因为你的数组被shell看作单行上的元素,用空格分隔; 而且因为sorting期望input是分开的。
  • sort -u – 只sorting和保留唯一的元素
  • tr '\n' ' ' – 将我们前面添加的换行符转换回空格。
  • $(...) – 命令取消
  • 除此之外: tr ' ' '\n' <<< "${ids[@]}"是一种更有效的方法: echo "${ids[@]}" | tr ' ' '\n' echo "${ids[@]}" | tr ' ' '\n'

如果你正在运行Bash版本4或更高版本(在任何现代版本的Linux中都应该是这种情况),可以通过创build一个包含原始数组的每个值的新关联数组,在bash中获得唯一的数组值。 像这样的东西:

 $ a=(aa ac aa ad "ac ad") $ declare -A b $ for i in "${a[@]}"; do b["$i"]=1; done $ printf '%s\n' "${!b[@]}" ac ad ac aa ad 

这是有效的,因为在一个数组中,每个键只能出现一次。 当for循环到达a[2]中的第二个aa值时,它将覆盖原来为a[0]设置的b[aa] a[0]

在本地bash中执行操作可能比使用pipe道和外部工具(如sortuniq更快。

如果你的数组元素有空格或其他shell特殊字符(你可以肯定他们没有?),那么首先要抓住这些(你应该总是这样做)用双引号表示你的数组! 例如"${a[@]}" 。 Bash将从字面上解释为“每个数组元素在一个单独的参数 ”。 在bash中总是这样工作。

然后,为了得到一个sorting(和唯一)的数组,我们必须将它转换为一个能够理解的格式,并能够将它转换回bash数组元素。 这是我所想到的最好的:

 eval a=($(printf "%q\n" "${a[@]}" | sort -u)) 

不幸的是,这在空数组的特殊情况下失败,将空数组转换为1个空元素的数组(因为printf有0个参数,但仍然打印,就好像它有一个空参数 – 请参阅解释)。 所以你必须在一个如果什么的东西。

说明:printf的%q格式“shell转义”打印的参数,就像bash可以在eval中那样恢复的方式一样! 因为每一个元素都是打印出来的,所以在它自己的行上转义了,元素之间的唯一分隔符就是换行符,数组赋值将每一行作为一个元素,将转义值parsing为文本文本。

例如

 > a=("foo bar" baz) > printf "%q\n" "${a[@]}" 'foo bar' baz > printf "%q\n" '' 

评估是必要的剥离每个值退回到数组。

我意识到这已经被回答了,但是在search结果中显示出相当高的水平,并且可能对某人有所帮助。

 printf "%s\n" "${IDS[@]}" | sort -u 

例:

 ~> IDS=( "aa" "ab" "aa" "ac" "aa" "ad" ) ~> echo "${IDS[@]}" aa ab aa ac aa ad ~> ~> printf "%s\n" "${IDS[@]}" | sort -u aa ab ac ad ~> UNIQ_IDS=($(printf "%s\n" "${IDS[@]}" | sort -u)) ~> echo "${UNIQ_IDS[@]}" aa ab ac ad ~> 

'sort'可以用来命令for循环的输出:

 for i in ${ids[@]}; do echo $i; done | sort 

并用“-u”消除重复项

 for i in ${ids[@]}; do echo $i; done | sort -u 

最后,你可以用独特的元素覆盖你的数组:

 ids=( `for i in ${ids[@]}; do echo $i; done | sort -u` ) 

这一个也将保持秩序:

 echo ${ARRAY[@]} | tr [:space:] '\n' | awk '!a[$0]++' 

并用唯一值修改原始数组:

 ARRAY=($(echo ${ARRAY[@]} | tr [:space:] '\n' | awk '!a[$0]++')) 

要创build一个由唯一值组成的新数组,请确保您的数组不为空,然后执行以下操作之一:

删除重复的条目(与sorting)

 readarray -t NewArray < <(printf '%s\n' "${OriginalArray[@]}" | sort -u) 

删除重复的条目(没有sorting)

 readarray -t NewArray < <(printf '%s\n' "${OriginalArray[@]}" | awk '!x[$0]++') 

警告:不要试图做一些像NewArray=( $(printf '%s\n' "${OriginalArray[@]}" | sort -u) ) 。 它会打破空间。

不失去原来的顺序:

 uniques=($(tr ' ' '\n' <<<"${original[@]}" | awk '!u[$0]++' | tr '\n' ' ')) 

猫号码.txt

 1 2 3 4 4 3 2 5 6 

将行打印到列: cat number.txt | awk 'BEGIN{FS=" "} {for(i=1;i<=NF;i++) print $i}' cat number.txt | awk 'BEGIN{FS=" "} {for(i=1;i<=NF;i++) print $i}'

 1 2 3 4 4 3 2 5 6 

find重复的logging: cat number.txt | awk 'BEGIN{FS=" "} {for(i=1;i<=NF;i++) print $i}' |awk 'x[$0]++' cat number.txt | awk 'BEGIN{FS=" "} {for(i=1;i<=NF;i++) print $i}' |awk 'x[$0]++'

 4 3 2 

replace重复logging: cat number.txt | awk 'BEGIN{FS=" "} {for(i=1;i<=NF;i++) print $i}' |awk '!x[$0]++' cat number.txt | awk 'BEGIN{FS=" "} {for(i=1;i<=NF;i++) print $i}' |awk '!x[$0]++'

 1 2 3 4 5 6 

只查找Uniqlogging: cat number.txt | awk 'BEGIN{FS=" "} {for(i=1;i<=NF;i++) print $i|"sort|uniq -u"} cat number.txt | awk 'BEGIN{FS=" "} {for(i=1;i<=NF;i++) print $i|"sort|uniq -u"}

 1 5 6 

试试这个来获得文件中第一列的uniq值

 awk -F, '{a[$1];}END{for (i in a)print i;}' 

如果你想要一个只使用bash内部的解决scheme,你可以在关联数组中设置键值,然后提取键值:

 declare -A uniqs list=(foo bar bar "bar none") for f in "${list[@]}"; do uniqs["${f}"]="" done for thing in "${!uniqs[@]}"; do echo "${thing}" done 

这将输出

 bar foo bar none