我有一个包含以下空格分隔条目的变量。
variable="apple lemon papaya avocado lemon grapes papaya apple avocado mango banana"
如何在不排序的情况下删除重复项?
#Something like this.
new_variable="apple lemon papaya avocado grapes mango banana"
我找到了一个脚本,可以完成删除变量的重复,但会对内容进行排序。
#Not something like this.
new_variable=$(echo "$variable"|tr " " "\n"|sort|uniq|tr "\n" " ")
echo $new_variable
apple avocado banana grapes lemon mango papaya
答案 0 :(得分:20)
new_variable=$( awk 'BEGIN{RS=ORS=" "}!a[$0]++' <<<$variable );
以下是它的工作原理:
RS(输入记录分隔符)设置为空格,以便将$ variable中的每个水果视为记录而不是字段。非排序独特的魔法发生在!a [$ 0] ++。由于awk支持关联数组,因此它使用当前记录($ 0)作为数组a []的键。如果之前没有看到该键,则[$ 0]计算为'0'(awk的未设置索引的默认值),然后否定返回TRUE。然后我利用awk默认为'print $ 0'的事实,如果表达式返回TRUE并且没有给出'{commands}'。最后,[$ 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;
答案 1 :(得分:6)
此管道版本的工作原理是保留原始订单:
variable=$(echo "$variable" | tr ' ' '\n' | nl | sort -u -k2 | sort -n | cut -f2-)
答案 2 :(得分:3)
Pure 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
答案 3 :(得分:3)
纯粹的便携式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
答案 4 :(得分:1)
壳
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}'
答案 5 :(得分:1)
Z Shell:
% variable="apple lemon papaya avocado lemon grapes papaya apple avocado mango banana"
% print ${(zu)variable}
apple lemon papaya avocado grapes mango banana
答案 6 :(得分:0)
另一个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
答案 7 :(得分:0)
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
此变化产生与最后一个相同的输出 但是,使用输入文件&#39; fruits&#39;而不是输入shell变量,每行一个水果:
perl -lne '$h{$_}++; END{ for (sort { $h{$a} <=> $h{$b} || $a cmp $b } keys %h){ print "$h{$_}\t$_" } }' fruits