我如何从Bash中的数组获得唯一值?
我有几乎和这里一样的问题。
我有一个数组,其中包含一个aa ab aa ac aa ad
等。现在我想从这个数组中select所有独特的元素。 以为,这将是简单的sort | uniq
sort | uniq
或sort -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道和外部工具(如sort
和uniq
更快。
如果你的数组元素有空格或其他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