UNIX kabuk komut dosyasındaki bir listeden benzersiz veya farklı değerler seçin


238

Newline ayrılmış değerler uzun bir liste döndüren bir ksh komut dosyası var ve yalnızca benzersiz / farklı değerleri görmek istiyorum. Bunu yapmak mümkün mü?

Örneğin, çıktımın bir dizindeki dosya sonekleri olduğunu varsayalım:

tar
gz
java
gz
java
tar
class
class

Şunun gibi bir liste görmek istiyorum:

tar
gz
java
class

Yanıtlar:


432

uniqVe sortuygulamalarına bakmak isteyebilirsiniz .

./yourscript.ksh | sırala | uniq

(Bilginize, evet, bu komut satırında sıralama gereklidir, uniqyalnızca birbirinin hemen arkasındaki yinelenen satırları çıkarır)

DÜZENLE:

Aaron Digulla tarafından uniqkomut satırı seçenekleriyle ilgili olarak yayınlananların aksine :

Aşağıdaki girdi verildiğinde:

sınıf
kavanoz
kavanoz
kavanoz
çöp Kutusu
çöp Kutusu
java

uniq tüm satırları tam olarak bir kez çıktılar:

sınıf
kavanoz
çöp Kutusu
java

uniq -d birden fazla görünen tüm satırların çıktısını alır ve bunları bir kez basar:

kavanoz
çöp Kutusu

uniq -u tam olarak bir kez görünen tüm satırların çıktısını alır ve bunları bir kez basar:

sınıf
java

2
Geç kalanlar için sadece bir FYI: @ AaronDigulla'nın cevabı düzeltildi.
mklement0

2
çok iyi bir nokta bu `` bu komut satırında sıralama gereklidir, uniq sadece yeni öğrendim hangi sadece birbiri ardına yinelenen satırları 'şeritler !!
HattrickNZ

4
GNU benzersiz değerleri vermek için sortbir -uversiyona sahiptir .
Arthur2e5

uniqDikişlerin sadece bitişik çizgileri (en azından varsayılan olarak) işlemek için olduğunu anladım, yani bir sortbeslemeden önce girilebilir uniq.
Stphane

85
./script.sh | sort -u

Bu, monoksitin cevabı ile aynıdır , ancak biraz daha özlüdür.


6
Mütevazısınız: çözümünüz de daha iyi performans gösterecektir (muhtemelen sadece büyük veri kümelerinde fark edilir).
mklement0

Bence bu ... | sort | uniqtek seferde yapıldığı için daha verimli olmalı
Adrian Antunez

10

Sıralamanın istenemeyeceği daha büyük veri kümeleri için aşağıdaki perl komut dosyasını da kullanabilirsiniz:

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

Bu temelde her hat çıkışını hatırlar, böylece tekrar çıkış yapmaz.

sort | uniqÖnünde hiçbir sıralama gerekmemesi " " çözümüne göre avantajlıdır .


2
Çok büyük bir dosyanın sıralanmasının kendi başına sıralama ile ilgili bir sorun olmadığını unutmayın; kullanılabilir RAM + takasından daha büyük dosyaları sıralayabilir. Sadece birkaç kopya varsa, Perl, OTOH başarısız olur.
Aaron Digulla

1
Evet, beklenen verilere bağlı olarak bir değiş tokuş. Perl, çok sayıda yinelenen büyük veri kümesi için daha iyidir (disk tabanlı depolama gerekmez). Birkaç yinelenen büyük veri kümesi sıralama (ve disk depolama) kullanmalıdır. Küçük veri kümeleri de kullanabilir. Şahsen, önce Perl'i denerdim, başarısız olursa sıralamaya geçerdim.
paxdiablo

Sıralama yalnızca diske takas etmesi durumunda size fayda sağladığı için.
paxdiablo

5
Her satırın ilk oluşumunu istediğimde bu harika. Sıralama bunu kırabilir.
Bluu

10

İle zsh bunu yapabilirsiniz:

% 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

Veya AWK'yı kullanabilirsiniz:

% awk '!_[$0]++' infile    
tar
more than one word
gz
java
class

2
Girdilerin sıralanmasını içermeyen akıllı çözümler. Uyarılar: Çok zekice ama şifreli awkçözüm ( açıklama için stackoverflow.com/a/21200722/45375 adresine bakın ), benzersiz satırların sayısı yeterince az olduğu sürece (benzersiz satırlar bellekte tutulduğu için) büyük dosyalarla çalışacaktır ). zshSolüsyon büyük dosyalarla bir seçenek olmayabilir, hangi önce belleğe dosyanın tamamını okur. Ayrıca, yazıldığı gibi, yalnızca gömülü alanı olmayan satırlar doğru şekilde işlenir; bunu düzeltmek için IFS=$'\n' read -d '' -r -A u <file; print -l ${(u)u}kullanın.
mklement0

Doğru. Veya:(IFS=$'\n' u=($(<infile)); print -l "${(u)u[@]}")
Dimitre Radoulov

1
Teşekkürler, bu daha basit (alt kabuk dışında gerekli değişkenleri ayarlamanız gerekmediğini varsayarsak). [@]Bir dizinin tüm öğelerine başvurmak için son eke ihtiyacınız olduğunda merak ediyorum - en azından sürüm 5'ten beri - o olmadan çalışır; Yoksa açıklık için mi eklediniz?
mklement0

1
@ mklement0, haklısın! Gönderiyi yazarken düşünmedim. Aslında, bu yeterli olmalı:print -l "${(fu)$(<infile)}"
Dimitre Radoulov

1
Fantastik, yazınızı güncellediğiniz için teşekkürler - Ben de awkörnek çıktı sabitleme özgürlüğü aldı .
mklement0

9

Boru onları içinden sortve uniq. Bu, tüm kopyaları kaldırır.

uniq -dyalnızca kopyaları uniq -uverir, yalnızca benzersiz olanları verir (kopyaları şeritler).


ilk bakışta sıralama
brabster

1
Evet yaparsın. Ya da daha doğrusu, tüm yinelenen satırları birlikte gruplamanız gerekir. Sıralama bunu tanım gereği yapar;)
Matthew Scharley

Ayrıca, uniq -uvarsayılan davranış DEĞİLDİR (ayrıntılar için
cevabımdaki

7

AWK ile yapabileceğiniz gibi, sıralamadan daha hızlı buluyorum

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

Kesinlikle bu işi yapmanın en sevdiğim yolu, çok teşekkürler! Özellikle daha büyük dosyalar için, sıralama | uniq-çözümleri muhtemelen istediğiniz şey değildir.
Schmitzi

1

İstendiği gibi benzersiz (ancak sıralanmamış);
~ 70'ten az eleman için daha az sistem kaynağı kullanır (zamanla test edildiği gibi);
stdin'den girdi almak için yazılmış,
(veya başka bir senaryoda değişiklik yapıp dahil edecek):
(Bash)

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[@]}"

0

Bir dosyada yinelenmeyen girişler almak için daha iyi ipuçları alıyorum

awk '$0 != x ":FOO" && NR>1 {print x} {x=$0} END {print}' file_name | uniq -f1 -u
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.