删除variables上的重复项而不进行sorting

我有一个variables,其中包含以下空格分隔条目。

variable="apple lemon papaya avocado lemon grapes papaya apple avocado mango banana" 

如何删除重复没有sorting

 #Something like this. new_variable="apple lemon papaya avocado grapes mango banana" 

我find了一个脚本来完成删除variables的重复,但sorting的内容。

 #Not something like this. new_variable=$(echo "$variable"|tr " " "\n"|sort|uniq|tr "\n" " ") echo $new_variable apple avocado banana grapes lemon mango papaya 

 new_variable=$( awk 'BEGIN{RS=ORS=" "}!a[$0]++' <<<$variable ); 

这是如何工作的:

RS(输入记录分隔符)被设置为一个空格,以便它将$ variable中的每个水果作为记录而不是字段。 非排序独特的魔术与!a [$ 0] ++发生。 由于awk支持关联数组,它使用当前记录($ 0)作为数组a []的关键字。 如果之前没有看到该键,则[$ 0]计算为'0'(awk的未设置索引的默认值),否则返回TRUE。 然后我利用这个事实,如果一个表达式返回TRUE并且没有给出'{commands}',那么awk将默认'打印$ 0'。 最后,一个[$ 0]然后递增,这个键不能再返回TRUE,因此重复值永远不会被打印。 ORS(输出记录分隔符)被设置为一个空格以模仿输入格式。

产生相同输出的这个命令的简短版本将如下所示:

 awk 'BEGIN{RS=ORS=" "}{ if (a[$0] == 0){ a[$0] += 1; print $0}}' 

得爱awk =)

编辑

如果你需要在纯Bash 2.1+中做到这一点,我会建议这样做:

 #!/bin/bash variable="apple lemon papaya avocado lemon grapes papaya apple avocado mango banana" temp="$variable" new_variable="${temp%% *}" while [[ "$temp" != ${new_variable##* } ]]; do temp=${temp//${temp%% *} /} new_variable="$new_variable ${temp%% *}" done echo $new_variable; 

这个管道版本的工作原理是保留原来的顺序:

 variable=$(echo "$variable" | tr ' ' '\n' | nl | sort -u -k2 | sort -n | cut -f2-) 

纯粹的Bash:

 variable="apple lemon papaya avocado lemon grapes papaya apple avocado mango banana" declare new_value='' for item in $variable; do if [[ ! $new_value =~ $item ]] ; then # first time? new_value="$new_value $item" fi done new_value=${new_value:1} # remove leading blank 

在纯粹的,便携式的sh

words="apple lemon papaya avocado lemon grapes papaya apple avocado mango banana" seen= for word in $words; do case $seen in $word\ * | *\ $word | *\ $word\ * | $word) # already seen ;; *) seen="$seen $word" ;; esac done echo $seen
words="apple lemon papaya avocado lemon grapes papaya apple avocado mango banana" seen= for word in $words; do case $seen in $word\ * | *\ $word | *\ $word\ * | $word) # already seen ;; *) seen="$seen $word" ;; esac done echo $seen 

贝壳

 declare -a arr variable="apple lemon papaya avocado lemon grapes papaya apple avocado mango banana" set -- $variable count=0 for c in $@ do flag=0 for((i=0;i<=${#arr[@]}-1;i++)) do if [ "${arr[$i]}" == "$c" ] ;then flag=1 break fi done if [ "$flag" -eq 0 ] ; then arr[$count]="$c" count=$((count+1)) fi done for((i=0;i<=${#arr[@]}-1;i++)) do echo "result: ${arr[$i]}" done 

运行结果:

 linux# ./myscript.sh result: apple result: lemon result: papaya result: avocado result: grapes result: mango result: banana 

或者如果你想使用gawk

 awk 'BEGIN{RS=ORS=" "} (!($0 in a) ){a[$0];print}' 

Z壳牌:

 % variable="apple lemon papaya avocado lemon grapes papaya apple avocado mango banana" % print ${(zu)variable} apple lemon papaya avocado grapes mango banana 

另一个awk解决方案:

 #!/bin/bash variable="apple lemon papaya avocado lemon grapes papaya apple avocado mango banana" variable=$(printf '%s\n' "$variable" | awk -v RS='[[:space:]]+' '!a[$0]++{printf "%s%s", $0, RT}') variable="${variable%,*}" echo "$variable" 

输出:

 apple lemon papaya avocado grapes mango banana 

Perl解决方案:

perl -le 'for (@ARGV){ $h{$_}++ }; for (keys %h){ print $_ }' $variable

@ARGV是来自$variable的输入参数列表
循环访问列表,用循环变量$_填充h散列
循环h散列的键,并打印每一个

 grapes avocado apple lemon banana mango papaya 

这个变化打印的输出先按频率$h{$a} <=> $h{$b}排序,然后按字母顺序排序$a cmp $b

perl -le 'for (@ARGV){ $h{$_}++ }; for (sort { $h{$a} <=> $h{$b} || $a cmp $b } keys %h){ print "$h{$_}\t$_" }' $variable

 1 banana 1 grapes 1 mango 2 apple 2 avocado 2 lemon 2 papaya 

这种变化会产生与最后一个相同的输出。
但是,而不是输入shell变量,使用输入文件“水果”,每行一个水果:

perl -lne '$h{$_}++; END{ for (sort { $h{$a} <=> $h{$b} || $a cmp $b } keys %h){ print "$h{$_}\t$_" } }' fruits