Polecenie powłoki systemu Linux do filtrowania pliku tekstowego według długości linii

19

Mam obraz dysku 30 GB zepsutej partycji (pomyśl dd if=/dev/sda1 of=diskimage), z którego muszę odzyskać niektóre pliki tekstowe. Narzędzia do rzeźbienia danych, takie jak foremosttylko pliki z dobrze zdefiniowanymi nagłówkami, tj. Nie zwykłe pliki tekstowe, spoczęły na moim dobrym przyjacielu strings.

strings diskimage > diskstrings.txt stworzyłem plik tekstowy 3 GB zawierający wiązkę ciągów, głównie niepotrzebnych rzeczy, zmieszany z tekstem, którego tak naprawdę chcę.

Większość cruft to naprawdę długie, nieprzerwane ciągi bełkotu. Rzeczy, które mnie interesują, mają na pewno mniej niż 16 KB, więc zamierzam filtrować plik według długości linii. Oto skrypt Pythona, którego używam do tego:

infile  = open ("infile.txt" ,"r");
outfile = open ("outfile.txt","w");
for line in infile:
    if len(line) < 16384:
        outfile.write(line)
infile.close()
outfile.close()

Działa to, ale do wglądu w przyszłości: Czy są jakieś magiczne inkantacje jednowierszowe (pomyśl awk, sed), które filtrowałyby plik według długości linii?

Li-aung Yip
źródło

Odpowiedzi:

28
awk '{ if (length($0) < 16384) print }' yourfile >your_output_file.txt

wypisze linie krótsze niż 16 kilobajtów, jak we własnym przykładzie.

Lub jeśli lubisz Perla:

perl -nle 'if (length($_) < 16384) { print }' yourfile >your_output_file.txt
Janne Pikkarainen
źródło
To było żenująco proste. Dziękuję Ci. :)
Li-aung Yip
Dodano także wersję Perla :-)
Janne Pikkarainen
A skrypt awk można zapisać jako awk 'length($0) < 16384' file > output, ponieważ domyślną czynnością jest wydrukowanie linii.
glenn jackman
8

Jest to podobne do odpowiedzi Ansgara, ale nieco szybsze w moich testach:

awk 'length($0) < 16384' infile >outfile

Jest taka sama prędkość jak inne odpowiedzi awk. Opiera się na domniemanym printprawdziwym wyrażeniu, ale nie musi poświęcać czasu na podzielenie linii, tak jak robi to Ansgar.

Pamiętaj, że AWK daje ci ifza darmo. Powyższe polecenie jest równoważne z:

awk 'length($0) < 16384 {print}' infile >outfile

Nie ma wyraźnego if(lub otaczającego go zestawu nawiasów klamrowych), jak w niektórych innych odpowiedziach.

Oto sposób na to sed:

sed '/.\{16384\}/d' infile >outfile

lub:

sed -r '/.{16384}/d' infile >outfile

które usuwają dowolny wiersz zawierający 16384 (lub więcej) znaków.

Dla kompletności, oto jak chcesz sedzapisać linie dłuższe niż próg:

sed '/^.\{0,16383\}$/d' infile >outfile
Wstrzymano do odwołania.
źródło
2

Możesz na awkprzykład:

$ awk '{ if (length($0) < 16384) { print } }' /path/to/text/file

Spowoduje to wydrukowanie linii dłuższych niż 16 000 znaków (16 * 1024).

Możesz użyć greprównież:

$ grep ".\{,16384\}" /path/to/text/file

Spowoduje to wydrukowanie wierszy maksymalnie 16 000 znaków.

Khaled
źródło
Nie jestem pewien, czy grepto dobry pomysł - to proste wyrażenie regularne, ale bardziej kosztowne obliczeniowo niż awk. „Mężczyzna z problemem mówi:„ Użyję wyrażeń regularnych! ”Teraz ma dwa problemy.” ;)
Li-aung Yip
To tylko kolejny sposób na zrobienie tego. Pierwszą opcją, którą opublikowałem, było użycie awk.
Khaled
1
+1 za
wyrażenie regularne, ponieważ gra w
2

Nie różni się tak naprawdę od już udzielonych odpowiedzi, ale wciąż jest krótszy:

awk -F '' 'NF < 16384' infile >outfile
Ansgar Esztermann
źródło