在UNIX shell脚本中从列表中选择唯一或不同的值

我有一个ksh脚本,它返回一个长列表的值,换行符分隔,我想只看到唯一的/不同的值。这是可能的吗?

例如,我的输出是一个目录下的文件后缀:

tar
gz
java
gz
java
tar
class
class

我想看到这样的列表:

tar
gz
java
class
386111 次浏览

你可能想看看uniqsort应用程序。

./yourscript.ksh | sort | uniq

(仅供参考,是的,排序在这个命令行中是必要的,uniq只去除紧挨着彼此的重复行)

编辑:

亚伦Digulla发布的有关uniq命令行选项的内容相反:

给定以下输入:

class
jar
jar
jar
bin
bin
java

uniq将只输出一次所有行:

class
jar
bin
java

uniq -d将输出所有出现超过一次的行,并打印一次:

jar
bin

uniq -u将输出恰好出现一次的所有行,并将它们打印一次:

class
java

通过sortuniq来管道它们。这将删除所有重复项。

uniq -d只给出重复项,uniq -u只给出唯一项(去除重复项)。

对于较大的数据集,排序可能是不可取的,你也可以使用以下perl脚本:

./yourscript.ksh | perl -ne 'if (!defined $x{$_}) { print $_; $x{$_} = 1; }'

它基本上只记住每一行输出,这样就不会再次输出。

与“sort | uniq”解决方案相比,它的优势在于不需要预先排序。

使用zsh你可以这样做:

% cat infile
tar
more than one word
gz
java
gz
java
tar
class
class
zsh-5.0.0[t]% print -l "${(fu)$(<infile)}"
tar
more than one word
gz
java
class

或者你可以使用AWK:

% awk '!_[$0]++' infile
tar
more than one word
gz
java
class
./script.sh | sort -u

这与一氧化的 回答相同,但更简洁一点。

唯一,根据请求,(但未排序) 对于小于~70个元素使用较少的系统资源(根据时间测试);
写入从stdin获取输入,
(或修改并包含在另一个脚本中):
(Bash) < / p >

bag2set () {
# Reduce a_bag to a_set.
local -i i j n=${#a_bag[@]}
for ((i=0; i < n; i++)); do
if [[ -n ${a_bag[i]} ]]; then
a_set[i]=${a_bag[i]}
a_bag[i]=$'\0'
for ((j=i+1; j < n; j++)); do
[[ ${a_set[i]} == ${a_bag[j]} ]] && a_bag[j]=$'\0'
done
fi
done
}
declare -a a_bag=() a_set=()
stdin="$(</dev/stdin)"
declare -i i=0
for e in $stdin; do
a_bag[i]=$e
i=$i+1
done
bag2set
echo "${a_set[@]}"

使用AWK你可以做到:

 ./yourscript.ksh | awk '!a[$0]++'

我发现它比sort和uniq快

我得到了一个更好的提示,以获得文件中不重复的条目

awk '$0 != x ":FOO" && NR>1 {print x} {x=$0} END {print}' file_name | uniq -f1 -u