Kürzen Sie die Linien und fügen Sie die Auslassungspunkte „…“ hinzu

7

Wie schneide ich Linien ab, die länger als eine gewisse Breite sind, und markiere die abgeschnittenen Linien mit einem Auslassungszeichen?

Es sollten nur Linien markiert werden, die tatsächlich gekürzt wurden, nicht jedoch Linien, die überhaupt die richtige Länge hatten.

Ich möchte den Befehl in einer Pipeline verwenden.

Volker Siegel
quelle
Möchten Sie die drei Zeichen ...oder das einzelne Zeichen verwenden ?
Mark Plotnick
Guter Punkt; Verwenden Sie für diese Frage die drei ".", Wie "...", da dies möglicherweise schwieriger ist als ein Auslassungszeichen.
Volker Siegel

Antworten:

13

Dadurch wird die Zeichenfolge abgeschnitten, weitere drei Zeichen abgeschnitten und "..." hinzugefügt, wenn die Länge länger als der Wert ist, den Sie als Parameter angeben.

other_programs | \
awk -v len=40 '{ if (length($0) > len) print substr($0, 1, len-3) "..."; else print; }'
Mark Plotnick
quelle
Das ist gut, es macht die Linien mit Auslassungspunkten so lang wie die längsten Linien! Und kümmert sich auch um die Berechnung der Länge.
Volker Siegel
7

Versuche dies:

awk -F '' '{if (NF > 70) {print substr($0, 0, 71)"..."} else print $0}'

Wenn NF zu hoch ist, ist der einfachere Weg:

awk '{if (length($0) > 70) {print substr($0, 0, 71)"..."} else print $0}'

oder eine kürzere Version:

awk 'length > 70{$0=substr($0,0,71)"..."}1'
muru
quelle
Entschuldigung für dieses Zitat. Kopier-Pasta-Auswahlfehler.
Muru
3
Dies führt bei einigen Geräten zu Fehlern awk, wenn die Länge größer als max NF. Beispiel, mawkhat max NF32767.
cuonglm
Wer auch immer die dritte Version hinzugefügt hat, sie hat keine Auslassungspunkte.
Muru
1
Entschuldigung, Tippfehler verpassen, aktualisiert.
Cuonglm
@ Gnouc danke für den kürzeren Befehl. Ich bin mir bei awk-Verknüpfungen nicht sehr sicher, daher verwende ich normalerweise standardmäßig längere Versionen. :)
Muru
5

Einige Möglichkeiten:

  • mit sed

    sed -E 's/(.{N})(.{1,})$/\1.../' file
    
  • etwas eleganter mit Perl (mit Lookbehind)

    perl -pe 's/(?<=.{N}).{1,}$/.../' file
    

Wo Nist die Anzahl der Zeichen, nach denen Sie durch die Auslassungspunkte ersetzen möchten?

Steeldriver
quelle
-E soll -e sein, nehme ich an? man sedweiß nicht-E
phil294
@Blauhirn -Esteht für E xtended Regular Expression - es ist das POSIX-Äquivalent der GNU sed -roder des --regex-extendedFlags. Es wird auf der Infoseite erwähnt, denke ich ( info seddann navigiere zu Invoking sed - Befehlszeilenoptionen )
steeldriver
3

awk, sedUnd perlwie in den anderen Antworten, präsentiert, zeichnen sich im Bereich Textverarbeitung und sind wahrscheinlich die besten Werkzeuge für den Job.

Sie können dies aber auch in reiner bashForm tun (dh "ohne die Hülle zu verlassen"), wenn Sie möchten:

n=70
while read -r; do
    if ((${#REPLY}<=n))
        then printf '%s\n' "$REPLY"
        else printf '%s...\n' "${REPLY:0:$((n-3))}"
    fi
done < filename

Ersetzen Sie 70durch die maximal gewünschte Länge und filenamedurch die Eingabedatei.

Um dies auf der rechten Seite einer Pipe zu verwenden (dh um die Ausgabe eines anderen Befehls an diese weiterzuleiten), entfernen Sie es und setzen Sie es entweder vorher ein oder schließen Sie das Ganze ein in :< filenamen{ ... ;}

{ n=70
while read -r; do
    if ((${#REPLY}<=n))
        then printf '%s\n' "$REPLY"
        else printf '%s...\n' "${REPLY:0:$((n-3))}"
    fi
done ;}

(Diese in Klammern eingeschlossene Version funktioniert auch in anderen Kontexten, einschließlich der Umleitung wie oben. Die Klammern sind in diesem Anwendungsfall nicht erforderlich, aber nicht schädlich.)

Das sieht so aus:

ek@Ilex:~$ help read | head -5 | { n=70
> while read -r; do
>     if ((${#REPLY}<=n))
>         then printf '%s\n' "$REPLY"
>         else printf '%s...\n' "${REPLY:0:$((n-3))}"
>     fi
> done ;}
read: read [-ers] [-a array] [-d delim] [-i text] [-n nchars] [-N n...
    Read a line from the standard input and split it into fields.

    Reads a single line from the standard input, or from file descr...
    if the -u option is supplied.  The line is split into fields as...

Beachten Sie, dass dies, wie bei den anderen bisher vorgestellten Lösungen, die Ausgabebreite bei Vorhandensein von Zeichen mit einer Breite von mehr als einer Spalte, z. B. horizontalen Registerkarten , nicht perfekt einschränkt .

Eliah Kagan
quelle
0

Eine andere perlLösung:

perl -ple '$_ = sprintf "%.70s...", $_ if length > 70' file
cuonglm
quelle
0

Die akzeptierte Antwort, die als Funktion mit Beispiel geschrieben wurde und auch das ... in die Mitte des Strings und nicht in das Ende setzt:

truncate() {    
    echo "$@" | \
    awk -v len=15 '{ if (length($0) > len) print substr($0, 1, len-3) "..." substr($0, length($0) - len, length($0)); else print; }'
}

Beispiel:

parse_branch() {
    branch=$(git symbolic-ref --short HEAD || hg branch)
    truncate "$branch"
}
OZZIE
quelle