Wie kann ich Zeilen in Dateien über eine bestimmte Länge identifizieren?

12

Ich möchte in meinem Code Zeilen finden, die eine bestimmte Länge überschreiten. Mein Code ist in mehreren Dateien. Was ist ein guter Weg, um dies zu tun?

Ich möchte die Dateien und Zeilennummern kennen; Inhalt wäre bevorzugt, aber nicht notwendig. Der Zweck der Übung ist es, dann herauszufinden, wie die Linien gebrochen werden (wahrscheinlich manuell).

Marcin
quelle
Wie wollen Sie die Ergebnisse? Als die Zeilen selbst (ihr Inhalt, wie in grep) oder als Zeilennummern oder als etwas anderes (vielleicht möchten Sie eine andere Aktion auf sie anwenden)? Der wahrscheinlich bequemste Weg, dies zu tun, hängt davon ab, was als nächstes mit diesen Zeilen geschehen wird.
imz - Ivan Zakharyaschev
@ imz - IvanZakharyaschev Guter Punkt. Frage aktualisiert.
Marcin

Antworten:

13

Mit grep:

grep -En '.{12}' file

Für Zeilen mit mindestens 12 Zeichen.

Mit mehreren Dateien:

find . -type f -exec grep -En '.{12}' {} +

Einige grepImplementierungen wie GNU grepkönnen die Dateisuche selbst durchführen.

grep -rEn '.{12}' .

Aber hüte dich vor Symlinks und anderen nicht regulären Dateien.

Stéphane Chazelas
quelle
Ich mag das, weil es einfach ist, und ich hatte gehofft, so etwas zu tun (bin immer noch nicht dazu gekommen).
Marcin
12

AWK-Lösung

awk '{       
if (length($0) > 5)
        print $0;'} yourfile

Oder genauer gesagt:

awk 'length > 5' file
Ramesh
quelle
9
Wir können Ihre Version kürzenawk 'length > 5'
am
Gnouc ist ein Brace Killer;)
Ouki
1
+1 fürawk 'length > 5'
3
Mit GNU awkdie etwas weniger elegante, aber prägnanteawk '/^.{6,}/'
iruvar
3
@ 1_CR, Das ist POSIX und kann verkürzt werden awk '/.{6}/'(tatsächlich war GNU awk bis vor kurzem derjenige, bei dem das nicht funktioniert, wenn Sie POSIXLY_CORRECT nicht an seine Umgebung übergeben).
Stéphane Chazelas
5

Da fehlte nur noch eine sedLösung

sed -n '/^.\{6,\}/p' file
iruvar
quelle
5

Bash-Lösung

#!/bin/bash

count=0

while read; do
    ((++count)) 
    len=${#REPLY}
    if ((len > 80)); then
        echo "Line $count is $len characters."
    fi
done

Also zB ./whatever.sh < input.file. Dies schließt den Zeilenumbruch durch Subtrahieren von 1 von nicht ein $len. Wenn dies nicht erwünscht ist oder Ihre Eingabe CRLF-Endungen verwendet, sollten Sie dies entsprechend anpassen.

Goldlöckchen
quelle
1
warum nicht ${#line}die exprGabel vermeiden ?
Iruvar
1
ha ha, +1 für die reine bashLösung. Beachten Sie jedoch, dass führende Leerzeichen ignoriert werden , sofern Sie nicht IFS=davor readbleiben.
Iruvar
1
Hinzugefügt in ein paar Bash Good Practices. Beachten Sie auch, dass der Zeilenumbruch nicht berücksichtigt wird und Sie $linekeinen abziehen müssen.
Iruvar
2
@ 1_CR Wenn Sie keinen readNamen zum Einlesen angeben , wird der REPLYgesamte Whitespace eingelesen und eingeschlossen. Keine IFSEinstellung erforderlich.
Kojiro
2
Das wird extrem langsam und behandelt die Backslash-Zeichen speziell. while readSchleifen zum Verarbeiten von Text sind wirklich eine schlechte Praxis.
Stéphane Chazelas
4

Mit perl(zum Beispiel), vorausgesetzt , Sie suchen nach Zeilen , die länger als 80 Zeichen:

So zeigen Sie die Zeilen an:

$ perl -nle 'print if length > 80' your_file

So zeigen Sie die Zeilennummer an:

$ perl -nle 'print "$.\n" if length > 80' your_file

Oder beides:

$ perl -nle 'print "[$.]:  $_\n" if length > 80' your_file
Ouki
quelle
3
Sie sollten eine -lBefehlszeile hinzufügen , um perlZeilenumbrüche in Ihren Zeilen zu zählen.
Dienstag,
1

Ruby:

ruby -lne 'puts $_ if $_.size > 5' intputfile

Python:

python -c "import sys;[ sys.stdout.write(''.join(line)) for line in sys.stdin if len(line.strip()) > 5 ]" < inputfile
Rahul Patil
quelle
1

Hier ist eine andere Bash-Lösung (Bash 4):

minlen=5 # minimum length of a line
mapfile -tO1 < inputfile # Map the file to the array MAPFILE (by default)
                         # Start the array at index 1
for i in "${!MAPFILE[@]}"; do
  (( ${#MAPFILE[i]} > minlen )) || unset MAPFILE[i] # Remove shorter elements
done

Das resultierende Array ist dünn, sodass die Array-Indizes beibehalten werden. Seit wir bei 1 angefangen haben, sind die Indizes die Zeilennummern der Zeilen, die wir behalten haben. Wir können nur diese Zeilennummern ausgeben:

printf 'Long lines found at: '
printf '%d, ' "${!MAPFILE[@]}"
echo

Oder wir können die Zeilen selbst ausgeben:

printf '%s\n' "${MAPFILE[@]}"
Kojiro
quelle