Ortak yollar yol / dosya listesinden nasıl bulunur


4

Prelude:

Bir yol / dosya listesi sıralı girişi göz önüne alındığında, ortak yolların nasıl bulunur?

Sıralanan girdiyi stdin'den beslerken, stdin'den en kısa öneki nasıl seçilir?

Burada "önek" normal bir anlama sahiptir, örneğin, "abcde" dizgisi "abc" önekine sahiptir. İşte benim örnek girdi

$ echo -e '/home/dave\n/home/dave/file1\n/home/dave/sub2/file2'
/home/dave
/home/dave/file1
/home/dave/sub2/file2

Bu, komutu kullanarak art arda uygun öneki stdin'den kaldırmak için bir örnektir sed:

$ echo -e '/home/dave\n/home/dave/file1\n/home/dave/sub2/file2' | sed "N; /^\(.*\)\n\1\//D; P; D" 
/home/dave/file1
/home/dave/sub2/file2

Soru:

Sorum şu , bunun yerine uygun öneki nasıl koruyacağınız ve bu öneki olan tüm satırları nasıl kaldıracağım. Her ikisi de sinüs /home/dave/file1ve /home/dave/sub2/file2öneki vardır /home/dave, /home/davediğer ikisi olmasa da korunacaktır. Yani, yukarıdaki sedkomutun tam tersini yapar.

Daha fazla bilgi:

  • Giriş zaten sıralanacaktı
  • Eğer /home/dave /home/dave/file1 /home/phil /home/phil/file2( echo -e '/home/dave\n/home/dave/file1\n/home/dave/sub2/file2\n/home/phil\n/home/phil/file2') varsa, beklerdim /home/daveve /home/philcevap olurdum .

Uygulama:

Benzer içerik içeren iki disk birimim var. V1’de olanı, ancak v2’den başka bir disk birimine, v3’e kopyalamak istiyorum. Kullanılması find, sortve commben kopyalamak için ne bir listesini elde edebilir, ama ben daha ileri o listeyi temizlemek gerekir. Yani /home/davelistede olduğum sürece diğer ikisine de ihtiyacım yok.

Teşekkürler!

Yanıtlar:


2

Bu cevap Python'u kullanır. OP, ebeveynleri tarafından kapsanan dizinleri bir olasılık olarak gördüğüm gibi kaldırmak istiyordu.

Örnek:

$ echo -e '/home/dave\n/home/dave/file1\n/home/dave/sub2/file2\n/home/phil\n/home/phil/file1' | removecoverings 
/home/phil
/home/dave

removecoveringsKomutun kodu :

#!/usr/bin/env python2

import sys

def list_startswith(a, b):
    if not len(a) >= len(b):
        return False
    return all(x == y for x,y in zip(a[:len(b)],b))

def removecoverings(it):
    g = list(it)
    g.sort(key=lambda v: len(v.split('/')), reverse=True)
    o = []
    while g:
        c = g.pop()
        d = []
        for v in g:
            if list_startswith(v.split('/'), c.split('/')):
                d.append(v)
        for v in d:
            g.remove(v)
        o.append(c)
    return o

for o in removecoverings(l.strip() for l in sys.stdin.readlines()):
    print o

Bu cevap Python'u kullanır. Ayrıca, string-wise ortak öneki yerine bir bileşen bilge yapar. Ortak önek olarak yolları için daha iyi /ex/ampleve /exa/mpleolması gerektiği /değil /ex. Bu, aranan şeyin en yaygın ortak önek olduğunu ve kapaklarının kaldırıldığı öneklerin bir listesi olmadığını varsayar. Eğer yerine /home/dave /home/dave/file1 /home/phil /home/phil/file2ve beklerseniz . Aradığın cevap bu değil./home/dave /home/phil/home

Örnek:

$ echo -e '/home/dave\n/home/dave/file1\n/home/dave/sub2/file2' | commonprefix 
/home/dave

commonprefixKomutun kodu :

#!/usr/bin/env python2

import sys

def commonprefix(l):
    # this unlike the os.path.commonprefix version
    # always returns path prefixes as it compares
    # path component wise
    cp = []
    ls = [p.split('/') for p in l]
    ml = min( len(p) for p in ls )

    for i in range(ml):

        s = set( p[i] for p in ls )         
        if len(s) != 1:
            break

        cp.append(s.pop())

    return '/'.join(cp)

print commonprefix(l.strip() for l in sys.stdin.readlines())

Teşekkürler, ben var maalesef eğer /home/dave /home/dave/file1 /home/phil /home/phil/file2, ben bekliyorsunuz ediyorum /home/daveve /home/philcevabı olmalıydı.
xpt

Teşekkürler Dan D. Girdinin zaten sıralanacağını vurgulamayı unuttum.
xpt

0

Girdi sıralandığında, sözde kod şöyle olurdu:

$seen = last_line;
if current_line begins exactly as $seen then next
else { output current_line; $seen = current_line }

Perl koduna çeviri (Evet, hepsinin en güzel senaryo dili olan Perl):

perl -e '
my $l = "\n";
while (<>) {
    if ($_ !~ /^\Q$l/) {
        print;
        chomp;
        $l = $_;
    }
}
'

Kredi: Ben Bacarisse @ bsb.me.uk, comp.lang.perl.misc adresinden. Teşekkürler Ben, harika çalışıyor!


İşte benim awkversiyonum:awk 'BEGIN{seen="\0"} { if (index($0,seen)==1) next; print $0; seen=$0; }'
xpt 6:14

0

Ve, xpt'in cevabının bir liner versiyonu. Yine, sıralanan giriş varsayarak:

perl -lne 'BEGIN { $l="\n"; }; if ($_ !~ /^\Q$l/) { print $_; $l = $_; }'

Örnek girişte koş

/home/dave
/home/dave/file1
/home/dave/sub2/file2
/home/phil
/home/phil/file2 

kullanma

echo -e '/home/dave\n/home/dave/file1\n/home/dave/sub2/file2\n/home/phil\n/home/phil/file2' | perl -lne 'BEGIN { $l="\n"; }; if ($_ !~ /^\Q$l/) { print $_; $l = $_; }'

verir

/home/dave
/home/phil

Büyü, perl komut satırında argümanlarda bulunur: -ekomut satırında bir komut dosyası yazmamıza izin verir -n, dosyanın satırlarının üzerinde yinelenir (her satırı yerleştirerek $_) ve -lbizim için yeni satırlarla ilgilenir.

Betik l, görülen son öneki izlemek için kullanılır . BEGINBlok ilk satır okunur önce çalıştırın ve (hiçbir satırsonu) görülmez bir dize değişkeni başlatır edilir. Koşullu, dosyanın her satırında çalıştırılır (tarafından tutulur $_). Koşullu, dosyanın tüm satırlarında yürütülür ve "satır lbir önek olarak geçerli değere sahip değilse, satırı yazdırın ve değeri olarak kaydedin " der l. Komut satırı argümanları nedeniyle, bu diğer komut ile özdeştir.

Her iki komutun da ortak ön ekin kendi satırı olarak bulunduğunu varsaydığı, bu nedenle

/home/dave/file1
/home/dave/file2

Teşekkürler. SU @vinegarbin'e hoş geldiniz. Lütfen örnek bir deneme çalıştırması gösterin (örn., echo -e '/home/dave\n/home/dave/file1\n/home/dave/sub2/file2\n/home/phil\n/home/phil/file2' | tee /dev/tty | perl -lane 'BEGIN { $l="\n"; }; if ($_ !~ /^\Q$l/) { print $_; $l = $_; }'Ve nasıl çalıştığını biraz açıklayın. Daha sonra +1 yapacağım ve sizinkileri kabul edeceğim.
xpt
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.