Yaklaşık 10 milyon satır içeren bir dosyam var.
Dosyadaki altı karakterden daha az olan tüm satırları kaldırmak istiyorum.
Bunu nasıl yaparım?
Yaklaşık 10 milyon satır içeren bir dosyam var.
Dosyadaki altı karakterden daha az olan tüm satırları kaldırmak istiyorum.
Bunu nasıl yaparım?
Yanıtlar:
Bunu yapmanın birçok yolu var.
Kullanma grep
:
grep -E '^.{6,}$' file.txt >out.txt
Şimdi out.txt
altı veya daha fazla karakter içeren satırlar olacak.
Ters yol:
grep -vE '^.{,5}$' file.txt >out.txt
sed
5 veya daha küçük uzunluktaki hatları kullanarak , kaldırarak:
sed -r '/^.{,5}$/d' file.txt
Ters yol, altı veya daha fazla uzunluktaki baskı hatları:
sed -nr '/^.{6,}$/p' file.txt
Çıkışı farklı bir dosyaya >
operatör kullanarak kaydedebilir grep
veya aşağıdaki -i
seçeneği kullanarak dosyayı yerinde düzenleyebilirsiniz sed
:
sed -ri.bak '/^.{6,}$/' file.txt
Orijinal dosya olarak yedeklenir file.txt.bak
ve değiştirilen dosya olur file.txt
.
Yedek tutmak istemiyorsanız:
sed -ri '/^.{6,}$/' file.txt
Kabuk kullanma, Yavaş, Bunu yapma , bu sadece başka bir yöntem göstermek uğruna:
while IFS= read -r line; do [ "${#line}" -ge 6 ] && echo "$line"; done <file.txt
Kullanılması python
, hatta daha yavaş grep
, sed
:
#!/usr/bin/env python2
with open('file.txt') as f:
for line in f:
if len(line.rstrip('\n')) >= 6:
print line.rstrip('\n')
Daha Pitonik olmak için liste kavrayışını daha iyi kullanın:
#!/usr/bin/env python2
with open('file.txt') as f:
strip = str.rstrip
print '\n'.join([line for line in f if len(strip(line, '\n')) >= 6]).rstrip('\n')
Çok basit:
grep ...... inputfile > resultfile #There are 6 dots
Bu şekilde, son derece verimli olduğunu grep
gerekenden fazla ayrıştırmak denemez, ne de herhangi bir şekilde karakter yorumlamak: basitçe Stdout'a bir (bütün) hattını (kabuk sonra resultfile adresine yönlendirir) göndermek en kısa sürede o 6 gördü bu satırdaki .
grafikler ( normal ifade bağlamında herhangi bir 1 karakterle eşleşir).
Bu nedenle grep, yalnızca 6 (veya daha fazla) karakter içeren satırlar çıkarır ve diğeri grep tarafından çıktılanmaz, böylece sonuç dosyasına ulaşmazlar.
En hızlı yol: Bu C programını derleyin ve çalıştırın:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_BUFFER_SIZE 1000000
int main(int argc, char *argv[]) {
int length;
if(argc == 3)
length = atoi(argv[2]);
else
return 1;
FILE *file = fopen(argv[1], "r");
if(file != NULL) {
char line[MAX_BUFFER_SIZE];
while(fgets(line, sizeof line, file) != NULL) {
char *pos;
if((pos = strchr(line, '\n')) != NULL)
*pos = '\0';
if(strlen(line) >= length)
printf("%s\n", line);
}
fclose(file);
}
else {
perror(argv[1]);
return 1;
}
return 0;
}
İle derleyin gcc program.c -o program
, ile çalıştırın ./program file line_length
(burada file
= dosya yolu ve line_length
= minimum satır uzunluğu, sizin durumunuzda 6
; maksimum satır uzunluğu 1000000
satır başına karakterlerle sınırlıdır ; değerini değiştirerek değiştirebilirsiniz MAX_BUFFER_SIZE
).
( Burada bulunan \n
ile değiştirme hilesi .)\0
Kabuk çözümü hariç bu soruya önerilen tüm diğer çözümlerle karşılaştırma (ortalama uzunluğu 8 karakter olan 10M satırlı ~ 91MB dosyada test çalıştırması):
time ./foo file 6
real 0m1.592s
user 0m0.712s
sys 0m0.160s
time grep ...... file
real 0m1.945s
user 0m0.912s
sys 0m0.176s
time grep -E '^.{6,}$'
real 0m2.178s
user 0m1.124s
sys 0m0.152s
time awk 'length>=6' file
real 0m2.261s
user 0m1.228s
sys 0m0.160s
time perl -lne 'length>=6&&print' file
real 0m4.252s
user 0m3.220s
sys 0m0.164s
sed -r '/^.{,5}$/d' file >out
real 0m7.947s
user 0m7.064s
sys 0m0.120s
./script.py >out
real 0m8.154s
user 0m7.184s
sys 0m0.164s
awk 'length>=6' file
length>=6
: length>=6
DOĞRU döndürürse, geçerli kaydı yazdırır.perl -lne 'length>=6&&print' file
lenght>=6
döner DOĞRU, geçerli kaydı yazdırır.% cat file
a
bb
ccc
dddd
eeeee
ffffff
ggggggg
% ./foo file 6
ffffff
ggggggg
% awk 'length>=6' file
ffffff
ggggggg
% perl -lne 'length>=6&&print' file
ffffff
ggggggg
awk
çözümü ..
sed
Çözümümü silmek zorunda kaldım (olur, biliyorum). XD
pos
Değişkenin anlamı nedir ? line
Newline karakteriyle karaktere bir işaretçi döndürür , ama asla kullanmıyormuş gibi görünüyorsunuz. Ve bulamazsanız, sadece ona eşitlersiniz \0
.
\0
( strchr()
karakter bulunmazsa NULL işaretçisi döndürür ). Buradaki nokta, her satırın sonundaki her satırın yerini \0
, satırsonu asla sayılmayacak şekilde değiştirmektir strlen()
: bu, son satırdaki potansiyel eksik satırdan bağımsız olarak uzunluk her zaman 6 ile karşılaştırılabilir. Sadece son çizgiye farklı davranmak çok daha verimli olur. Muhtemelen bunu daha sonra güncelleyeceğim.
grep
Aynı dosyada çözümü test ettim ve aslında daha hızlı (muhtemelen strlen()
burada en iyi fikir olmadığı için) . Bunun getchar()
yerine sadece ilk N karakterini kontrol etmek için bir döngü kullanmaya çalışacağım , sanırım bunu gözle görülür şekilde geliştirmeliyiz. Ve evet, tamponun uzunluğu üzerindeki herhangi bir çizgi sadece tamponun uzunluğuna kesilir.
Vim'i Ex modunda kullanabilirsiniz:
ex -sc 'v/\v.{6}/d' -cx file
\v
sihri aç
.{6}
6 veya daha fazla karakter içeren satırları bulma
v
zıt seçim
d
silmek
x
kaydet ve kapat
Ruby çözümü:
$ cat input.txt
abcdef
abc
abcdefghijk
$ ruby -ne 'puts $_ if $_.chomp.length() >= 6 ' < input.txt
abcdef
abcdefghijk
Basit fikir: dosyayı ruby'nin stdin'e yönlendirin ve stdin'den sadece 6 veya daha büyük bir uzunluksa satır yazdırın