Bash - her dosya satırını eşle


10

Bu soru, bu ve bu soru ile yakından ilgilidir . Her satır bir dosya yolu olduğu birkaç satır içeren bir dosya var. Şimdi her satırı her bir farklı satırla (kendisiyle değil) eşleştirmek istiyorum . Ayrıca bir çift benim amacım A Biçin bir B Açifte eşittir , bu nedenle bu kombinasyonlardan sadece biri üretilmelidir.

Misal

files.dat steno gösterimle böyle okur, her harf bir dosya yoludur (mutlak veya göreli)

a
b
c
d
e

Sonra benim sonuç şöyle görünmelidir:

a b
a c
a d
a e
b c
b d
b e
c d
c e
d e

Tercihen bunu bash'da çözmek istiyorum. Diğer soruların aksine, dosya listem oldukça küçük (yaklaşık 200 satır), bu yüzden döngüler ve RAM kapasitesi kullanmak sorun yaratmıyor.


Böyle olmak zorunda mıdır bash doğru veya bash komut yoluyla ulaşılabilir bir şey? Diğer yardımcı programlar metni işlemek için daha iyi konumlandırılmıştır.
Jeff Schaller

@JeffSchaller Bash komut satırı üzerinden erişilebilen bir şey. Biraz belirsizdim, üzgünüm
Enno

Bu neredeyse bir Kod Golfü haline geliyor : P
Richard de Wit

3
Genel bir kural olarak, önemsiz olmayan bir şey yapmanız gerektiği sürece, BASH üzerinden en sevdiğiniz kodlama dilini kullanın. Daha az kırılgan olacaktır (örneğin, özel karakterlere veya boşluklara karşı) ve ihtiyacınız olduğunda genişletmeniz çok daha kolay olacaktır (üçe ihtiyacınız varsa veya bazılarını filtreleyerek). Python veya Perl hemen hemen her Linux kutusuna kurulmalıdır, bu yüzden iyi seçimlerdir (Busybox gibi gömülü sistemler üzerinde çalışmıyorsanız).
Davidmh

Yanıtlar:


7

Bu komutu kullanın:

awk '{ name[$1]++ }
    END { PROCINFO["sorted_in"] = "@ind_str_asc"
        for (v1 in name) for (v2 in name) if (v1 < v2) print v1, v2 }
        ' files.dat

PROCINFObir gawkuzantı olabilir . Eğer awkbunu desteklemiyorsa, PROCINFO["sorted_in"] = "@ind_str_asc"hattı dışarıda bırakın ve çıkışı boruya bağlayın sort(eğer çıkışın sıralanmasını istiyorsanız).

(Bu mu değil sıralanmasını giriş yapılmalıdır.)


8
$ join -j 2 -o 1.1,2.1 file file | awk '!seen[$1,$2]++ && !seen[$2,$1]++'
a b
a c
a d
a e
b c
b d
b e
c d
c e
d e

Bu, girdi dosyasındaki hiçbir satırın boşluk içermediğini varsayar. Ayrıca dosyanın sıralandığını varsayar .

joinKomut dosyasında hatlarının tam çapraz ürünü oluşturur. Bunu, var olmayan bir alanda dosyayı kendisi ile birleştirerek yapar. Standart olmayanlar -j 2ile değiştirilebilir -1 2 -2 2(ancak -j2GNU kullanmadığınız sürece değiştirilemez join).

awkKomut bu sonucunu okur ve sadece henüz görülmemiştir çiftleri sonuçlar verir.


Ne demek "dosya sıralanır"? Hangi ölçütlere göre sıralandı?
Enno

@Enno Sıralama şekli sıralandı sort -b. joinsıralanmış girdi dosyaları gerektirir.
Kusalananda

8

Bir pythonçözüm. Giriş dosyası, itertools.combinationsstandart çıktıya biçimlendirilmiş ve yazdırılmış 2 uzunluklu tuples oluşturan standart kitaplıktan beslenir .

python3 -c 'from itertools import combinations
with open("file") as f:
    lines = (line.rstrip() for line in f)
    lines = ("{} {}".format(x, y) for x, y in combinations(lines, 2))
    print(*lines, sep="\n")
'

6

Eğer varsa rubykurulu:

$ ruby -0777 -F'\n' -lane '$F.combination(2) { |c| puts c.join(" ")}' ip.txt
a b
a c
a d
a e
b c
b d
b e
c d
c e
d e
  • -0777 dosyanın tamamını küçültün (OP'de dosya boyutunun küçük olduğu belirtildiği gibi iyi olmalıdır)
  • -F'\n'yeni satıra göre bölün, böylece her satır $Fdizideki bir öğe olacaktır
  • $F.combination(2)2tek seferde kombinasyon öğeleri oluşturma
  • { |c| puts c.join(" ")} gerektiği gibi yazdır
  • giriş dosyası kopyalar içeriyorsa, $F.uniq.combination(2)


bir seferde 3 eleman için:

$ ruby -0777 -F'\n' -lane '$F.combination(3) { |c| puts c.join(" ")}' ip.txt
a b c
a b d
a b e
a c d
a c e
a d e
b c d
b c e
b d e
c d e


İle perl(genel değil)

$ perl -0777 -F'\n' -lane 'for $i (0..$#F) {
                             for $j ($i+1..$#F) { 
                               print "$F[$i] $F[$j]\n" } }' ip.txt
a b
a c
a d
a e
b c
b d
b e
c d
c e
d e


İle awk

$ awk '{ a[NR]=$0 }
       END{ for(i=1;i<=NR;i++)
              for(j=i+1;j<=NR;j++)
                print a[i], a[j] }' ip.txt 
a b
a c
a d
a e
b c
b d
b e
c d
c e
d e

5

İşte saf kabukta bir tane.

test $# -gt 1 || exit
a=$1
shift
for f in "$@"
do
  echo $a $f
done
exec /bin/sh $0 "$@"

Misal:

~ (137) $ sh test.sh $(cat file.dat)
a b
a c
a d
a e
b c
b d
b e
c d
c e
d e
~ (138) $ 

1
Gibi bir şey ile daha iyi durumda olduğuna çok Komut ikamesi şeritler, yeni satır sondaki <file.dat xargs test.shdahatest.sh $(cat file.dat)
Iruvar

1

Kullanarak Perlbiz gösterildiği gibi yapabilirsiniz:

$ perl -lne '
     push @A, $_}{
     while ( @A ) {
        my $e = shift @A;
        print "$e $_" for @A;
     }
' input.txt
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.