Выберите уникальные или отличные значения из списка в сценарии оболочки UNIX
у меня есть скрипт ksh, который возвращает длинный список значений, разделенных новой строкой, и я хочу видеть только уникальные/отличные значения. Можно ли это сделать?
например, скажем, что мой вывод-это суффиксы файлов в каталоге:
tar gz java gz java tar class class
Я хочу увидеть список, как:
tar gz java class
7 ответов:
вы можете посмотреть на
uniq
иsort
приложения../yourscript.ksh | sort | uniq(к вашему сведению, да, сортировка необходима в этой командной строке,
uniq
только полосы дублируют линии, которые находятся сразу после друг друга)EDIT:
вопреки тому, что написал Аарон Digulla в отношении
uniq
параметры командной строки:учитывая следующие данные:
class jar jar jar bin bin java
uniq
выведет все строки ровно один раз:class jar bin java
uniq -d
выведет все строки, которые появляются более одного раза, и он будет печатать их один раз:jar bin
uniq -u
выведет все строки, которые появляются ровно один раз, и он будет печатать их один раз:class java
для больших наборов данных, где сортировка может быть нежелательной, вы также можете использовать следующий скрипт perl:
./yourscript.ksh | perl -ne 'if (!defined $x{$_}) { print $_; $x{$_} = 1; }'
это в основном просто запоминает каждый вывод строки, так что он не выводит его снова.
Он имеет преимущество перед "
sort | uniq
" решение в том, что сортировка не требуется заранее.
С zsh можно сделать так:
zsh-5.0.0[t]% 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:
zsh-4.3.9[t]% awk '!_[]++' infile tar more than one word gz java class
труба их через
sort
иuniq
. Это удаляет все дубликаты.
uniq -d
выдает только дубликаты,uniq -u
дает только уникальные (полосы дубликатов).
уникальный, как и просили, (но не отсортированный);
использует меньше системных ресурсов для менее чем ~70 элементов (как проверено временем);
написано, чтобы принять вход от stdin,
(или изменить и включить в другой скрипт):
(Баш)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]=$'' for ((j=i+1; j < n; j++)); do [[ ${a_set[i]} == ${a_bag[j]} ]] && a_bag[j]=$'' 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[@]}"