Unix'te bir dosyadaki yinelenen satırları silmenin bir yolu var mı?
Bunu sort -uve uniqkomutlarıyla yapabilirim, ancak sedveya kullanmak istiyorum awk. Mümkün mü?
awk, ancak daha büyük dosyalarda oldukça kaynak tüketecek.
Unix'te bir dosyadaki yinelenen satırları silmenin bir yolu var mı?
Bunu sort -uve uniqkomutlarıyla yapabilirim, ancak sedveya kullanmak istiyorum awk. Mümkün mü?
awk, ancak daha büyük dosyalarda oldukça kaynak tüketecek.
Yanıtlar:
awk '!seen[$0]++' file.txt
seenAwk'nin dosyanın her satırını ileteceği ilişkilendirilebilir bir dizidir. Dizide bir satır yoksa, seen[$0]yanlış olarak değerlendirilir. !Mantıksal DEĞİL operatörüdür ve true false tersine çevirir. Awk, ifadenin doğru olarak değerlendirildiği satırları yazdırır. ++Artışlarla seenböylece seen[$0] == 1sonra ilk kez bir satır ve daha sonra bulunan seen[$0] == 2, ve böyle devam eder.
Awk, 0ve ""(boş dize) dışındaki her şeyi doğru olarak değerlendirir. Yinelenen bir çizgi yerleştirilirse seeno zaman !seen[$0]false olarak değerlendirecektir ve çizgi çıktı yazılır edilmeyecektir.
awk '!seen[$0]++' merge_all.txt > output.txt
for f in *.txt; do gawk -i inplace '!seen[$0]++' "$f"; done
Gönderen http://sed.sourceforge.net/sed1line.txt : (nasıl bu işleri bana sormayın lütfen ;-))
# delete duplicate, consecutive lines from a file (emulates "uniq").
# First line in a set of duplicate lines is kept, rest are deleted.
sed '$!N; /^\(.*\)\n\1$/!P; D'
# delete duplicate, nonconsecutive lines from a file. Beware not to
# overflow the buffer size of the hold space, or else use GNU sed.
sed -n 'G; s/\n/&&/; /^\([ -~]*\n\).*\n\1/d; s/\n//; h; P'
$!kısım gerekli? sed 'N; /^\(.*\)\n\1$/!P; D'Aynı şeyi yapmıyor mu ? Makinemde ikisinin farklı olduğu bir örnek bulamıyorum (fwiw her iki sürümün sonunda boş bir satır denedim ve her ikisi de iyi).
[ -~]0x20 (boşluk) ile 0x7E (tilde) arasındaki bir ASCII karakter aralığını temsil eder. Bunlar kabul edilir yazdırılabilir ASCII karakterleri (bağlantılı sayfa ayrıca 0x7F / silme vardır ama bu doğru görünmüyor). Bu, ASCII kullanmayan veya sekme karakterleri kullanmayanlar için çözümü bozar. Daha taşınabilir olan çok daha fazla karakter içerir… aslında biri hariç hepsi. [^\n]
@ Jonas'ın awk çözümüne benzer Perl tek satırlık:
perl -ne 'print if ! $x{$_}++' file
Bu varyasyon, karşılaştırmadan önce sondaki beyaz boşluğu kaldırır:
perl -lne 's/\s*$//; print if ! $x{$_}++' file
Bu varyasyon, dosyayı yerinde düzenler:
perl -i -ne 'print if ! $x{$_}++' file
Bu varyasyon, dosyayı yerinde düzenler ve bir yedek oluşturur file.bak
perl -i.bak -ne 'print if ! $x{$_}++' file
Yukarıda Andre Miller'ın gönderdiği tek satırlık, giriş dosyası boş bir satırla ve karakter olmadan sona erdiğinde sed'in son sürümleri dışında çalışır. Mac'imde CPU'm sadece dönüyor.
Son satır boşsa ve karakter içermiyorsa sonsuz döngü :
sed '$!N; /^\(.*\)\n\1$/!P; D'
Takılmıyor ama son satırı kaybediyorsun
sed '$d;N; /^\(.*\)\n\1$/!P; D'
Açıklama sed SSS'nin en sonunda yer almaktadır :
GNU sed bakımcısı
, bunun neden olabileceği taşınabilirlik sorunlarına rağmen,
model alanını yazdırmak için ( silmek yerine ) N komutunu değiştirmenin,
"Sonraki satırı ekleme" komutunun nasıl davranması gerektiğine dair kişinin sezgileriyle daha tutarlı olduğunu hissetti .
Değişikliği destekleyen bir başka gerçek de, "{N; command;}"
dosyasında tek sayıda satır varsa son satırı silecek, ancak dosyanın çift sayıda
satırı varsa son satırı yazdıracak olmasıdır.N'nin önceki davranışını (EOF'ye
ulaştıktan sonra desen alanını silme) kullanan komut dosyalarını sed'in
tüm sürümleriyle uyumlu komut dosyalarına dönüştürmek için tek bir "N" değiştirin; "$ d; N;" .
$ echo -e '1\n2\n2\n3\n3\n3\n4\n4\n4\n4\n5' |sed -nr '$!N;/^(.*)\n\1$/!P;D'
1
2
3
4
5
ana fikir şudur:
print ONLY once of each duplicate consecutive lines at its LAST appearance and use D command to implement LOOP.
açıklar:
$!N;: mevcut satır son satır DEĞİLSE N, sonraki satırı okumak için komutu kullanın pattern space./^(.*)\n\1$/!P: Akımının içeriğini eğer pattern spaceiki duplicate stringayrılmış \nbir sonraki çizgi anlamına gelir, samemevcut satır bizim temel fikrine göre, de Yazdıramıyor; aksi halde, geçerli satırı anlamına gelen onun yinelenen ardışık hatlarının tümünün SON görünümü, biz şimdi kullanabilirsiniz Pakım karakter yazdırmak için komutu pattern spaceutil \n( \nayrıca yazdırılır).D: Kullandığımız Dakım karakter silmek için komut pattern spaceutil \n( \ndaha sonra içeriği de silindi) pattern spacesonraki çizgidir.Dkomut zorlar sedonun atlamak için FIRSTkomuta $!Nancak dosya veya standart girdi akışından sonraki satırını okumak DEĞİL.$ echo -e '1\n2\n2\n3\n3\n3\n4\n4\n4\n4\n5' |sed -nr 'p;:loop;$!N;s/^(.*)\n\1$/\1/;tloop;D'
1
2
3
4
5
ana fikir şudur:
print ONLY once of each duplicate consecutive lines at its FIRST appearance and use : command & t command to implement LOOP.
açıklar:
:loopkomutu bir seti labeladında loop.Ndoğru bir sonraki satırını okumak için pattern space.s/^(.*)\n\1$/\1/mevcut satırı silmek için sonraki satır mevcut satırla aynıysa s, deleteeylemi yapmak için komut kullanırız .skomut başarılı bir şekilde çalıştırılırsa, o zaman adlandırılmışa atlamak için tloopkomut kuvvetini sedkullanın , bu aynı döngüyü sonraki satırlara yapacak olan satırın ardışık yinelenen satırları yoktur ; aksi takdirde, satırla aynı olan komutu kullanın ve ilk komuta atlamaya zorlayın , bu komuttur, akımın içeriği sonraki yeni satırdır.labellooplatest printedDdeletelatest-printed linesedppattern spacebusybox echo -e "1\n2\n2\n3\n3\n3\n4\n4\n4\n4\n5" | busybox sed -nr "$!N;/^(.*)\n\1$/!P;D"
cat filename | sort | uniq -c | awk -F" " '$1<2 {print $2}'
Awk kullanarak yinelenen satırları siler.
catuniq
uniq, o zaman tek başına yeterlidir.