Bash'de iki listenin kesişimi


163

İki listede bulunan içeriği listeleyecek basit bir komut dosyası yazmaya çalışıyorum. Basitleştirmek için ls'yi örnek olarak kullanalım. "Bir" ve "iki" nin dizin olduğunu düşünün.

one = `ls one`
iki = `ls iki`
kavşak $ bir $ iki

Ben hala bash oldukça yeşil, bu yüzden bunu nasıl yaptığımı düzeltmekten çekinmeyin. Sadece "bir" ve "iki" tüm dosyaları yazdıracak bazı komut gerekir. Her ikisinde de var olmalıdırlar. Buna "bir" ile "iki" arasındaki "kavşak" diyebilirsiniz.


Burada hiçbir şey şu soruyu cevaplamıyor: Bash betiğinde iki değişkenin kesişimi .
jameshfisher

Bence yeni bir soru gibi görünüyor, bu soru burada açıkça cevaplanıyor.
Jean-Christophe Meillaud

Yanıtlar:


285
comm -12  <(ls 1) <(ls 2)

37
commBugüne kadar hiç bilgim olmadığına inanamıyorum . Bu sadece benim bütün hafta yaptı :)
Darragh Enright

22
commgirişlerin sıralanmasını gerektirir. Bu durumda, lsçıktısını otomatik olarak sıralar, ancak diğer kullanımların bunu yapması gerekebilir:comm -12 <(some-command | sort) <(some-other-command | sort)
Alexander Bird

11
Ls 'çıkışını herhangi bir şey için KULLANMAYIN. ls, etkileşimli olarak dizin meta verilerine bakmak için bir araçtır. Ls çıktısını kodla ayrıştırma denemesi bozuldu. Globs çok daha basit ve doğrudur: '' * .txt dosyasındaki ''. Oku mywiki.wooledge.org/ParsingLs
Rany Albeg Wein

2
Ben sadece bir özellik tarafından sağlanan bir publicyöntemin kullanımlarını bulmak için bir çaba error()ile birlikte kullanılan git grepve o was awesome! Ben koştum $ comm -12 <(git grep -il "\$this->error(" -- "*.php") <(git grep -il "Dash_Api_Json_Response" -- "*.php")ve neyse ki sadece özelliği içeren dosya adı ile sona erdi.
localheinz

3
Bu komik. Awk ile çılgınca şeyler yapmaya çalışıyordum.
Rolf

55

İle çözüm comm

commharika ama gerçekten sıralı liste ile çalışmak gerekir. Ve neyse ki burada kullanacağımız lsdan hangi lsBash adam sayfası

-CftuSUX veya --sort karakterlerinden hiçbiri yoksa girdileri alfabetik olarak sıralayın.

comm -12  <(ls one) <(ls two)

Alternatif sort

İki listenin kesişimi:

sort <(ls one) <(ls two) | uniq -d

iki listenin simetrik farkı:

sort <(ls one) <(ls two) | uniq -u

Bonus

Onunla oyna ;)

cd $(mktemp -d) && mkdir {one,two} && touch {one,two}/file_{1,2}{0..9} && touch two/file_3{0..9}

2
Tamamlayıcı yerine, bence genellikle simetrik fark denir .
Andrew Lazarus

29

commKomutunu kullanın :

ls one | sort > /tmp/one_list
ls two | sort > /tmp/two_list
comm -12 /tmp/one_list /tmp/two_list

"sıralama" gerçekten gerekli değildir, ancak her durumda "comm" kullanmadan önce her zaman dahil.


5
Sıralanması gerektiği için dahil etmek iyi ve sadece örnek olarak ls kullandı.
Thor84no

3

Daha az verimli (comm'den) bir alternatif:

cat <(ls 1 | sort -u) <(ls 2 | sort -u) | uniq -d

1
Eğer komut Debian'ın / bin / çizgi veya başka olmayan Bash kabuğunu kullanıyorsanız, size parantez zincir komutları çıkışını kullanarak yapabilirsiniz: (ls 1; ls 2) | sort -u | uniq -d.
azot

1
@ MikaëlMayer Yanıtladığınız kişinin adını işaretlemelisiniz, aksi takdirde beni kastettiği varsayılır.
Benubird

@nitrogen MikaëlMayer doğrudur - chainging sort -u | uniq -dhiçbir şey yapmaz, çünkü uniq, onları aramaya başlamadan önce kopyaları kaldırmıştır. Bence emrimin ne yaptığını anlamadın.
Benubird

@ Benubird Ben de cat <(ls 1 | sort -u) <(ls 2 | sort -u) | uniq -dhiçbir şey çıktı komutunu alamadım . Komutum liste kesişimini göstermek (ls 1; ls 2) | sort | uniq -diçin okumalı -u. @ MikaëlMayer orijinal komutumun kırıldığı konusunda haklıydı.
azot

@nitrogen Kedi kullanmamın sebebi bunun genelleştirilebilir bir çözüm olmasını istememdir, böylece lsbaşka bir şeyle değiştirebilirsiniz , örn find. Çözümünüz buna izin vermez, çünkü komutlardan biri iki satırı aynı döndürürse, yinelenen olarak alır. Kullanıcı ls 1/*, alt dizinlerdeki tüm dosyaları yapmak ve karşılaştırmak istese bile Mine çalışır . Aksi takdirde evet de işe yarıyor. Benimki bash'a özgü olabilir.
Benubird

2

Birleştirme, girdiye ve istenen çıktıya bağlı olarak iyi bir seçenektir

join -j1 -a1 <(ls 1) <(ls 2)

-1

Bunun bir kopyası olarak işaretlenen başka bir Stackoverflow sorusu olan "bash'de dizi kesişimi" var. Bence bu soru iki bash dizisini karşılaştırmaktan bahsederken, bu soru bash dosyalarına odaklanıyor. Şu anda kapalı olan diğer soruya bir satırlık cevap aşağıdaki gibidir:

# List1=( 0 1 2 3 4   6 7 8 9 10 11 12)
# List2=(   1 2 3   5 6   8 9    11 )
# List3=($(comm -12 <(echo ${List1[*]}| tr " " "\n"| sort) <(echo ${List2[*]} | tr " " "\n"| sort)| sort -g))
# echo ${List3[*]}
1 2 3 6 8 9 11

Comm yardımcı programı alfasayısal bir sıralama yaparken, "bash'deki Array kesişimi" yanıtları sayı kullanır; dolayısıyla "sort" ve "sort -g" kullanımı.

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.