Die ersten [x] Zeichen für einen String aus einer Pipe holen

58

Wenn ich wirklich lange Ausgaben von einem Befehl (einzelne Zeile) habe, aber ich weiß, dass ich nur die ersten [x] (sagen wir 8) Zeichen der Ausgabe haben möchte, wie kann ich das am einfachsten erreichen? Es gibt keine Begrenzer.

Xenoterracid
quelle

Antworten:

82

Ein Weg ist zu benutzen cut:

 command | cut -c1-8

Dies gibt Ihnen die ersten 8 Zeichen jeder Ausgabezeile. Da cutes Teil von POSIX ist, ist es wahrscheinlich auf den meisten Unices.

Steven D
quelle
3
Beachten Sie, dass cut -cZeichen ausgewählt werden. cut -boder head -cwählt Bytes aus. Dies macht in einigen Regionen einen Unterschied (in der Praxis bei Verwendung von UTF-8).
Gilles 'SO - hör auf böse zu sein'
Sie müssen in diesem Fall auch nicht den Startindex angeben. Das Sprichwort cut -c-8wählt zwischen 1 und 8.
Sparhawk
@Steven, ist cutdas Äquivalent unter Windows?
Pacerier
Auch command | dd bs=8 count=1 2>/dev/null. Das heißt nicht, dass es kürzer oder besser ist. Nur eine andere Alternative.
dubiousjim
@Gilles, aber beachten Sie, dass mit dem aktuellen Versionen von GNU cut, cut -cfunktioniert wie cut -b(das heißt, es funktioniert nicht richtig für Multi-Byte - Zeichen).
Stéphane Chazelas
24

Dies sind einige andere Möglichkeiten, um nur die ersten 8 Zeichen zu erhalten.

command | head -c8

command | awk '{print substr($0,1,8);exit}' 

command | sed 's/^\(........\).*/\1/;q'

Und wenn Sie Bash haben

var=$(command)
echo ${var:0:8}
user1606
quelle
2
Ich denke , die folgende sed Formulierung ein bisschen leichter zu lesen ist: command | sed 's/\(.\{8\}\).*/\1/'oder wenn Ihr unterstützt sie sed: command | sed -r 's/(.{8}).*/\1/'; Andernfalls +1
Steven D
Good stuff, aber beachten Sie, dass head -czählt Bytes , nicht Zeichen. In ähnlicher Weise behandelt unter den wichtigsten Awk-Implementierungen nur GNU awk Multibyte-Zeichen korrekt - FreeBSD Awk und Mawk nicht.
mklement0
2

Wenn Sie über eine ausreichend fortgeschrittene Shell verfügen (z. B. funktioniert Folgendes in Bash, wenn Sie sich nicht sicher sind, was das Bindestrich angeht), können Sie Folgendes tun:

read -n8 -d$'\0' -r <(command)

Nach der Ausführung befinden read ... <(command)sich Ihre Zeichen in der Shell-Variablen REPLY. Geben Sie ein help read, um weitere Optionen zu erfahren.

Erklärung: Das -n8Argument zu readbesagt, dass wir bis zu 8 Zeichen wollen. Das -d$'\0'sagt gelesen bis eine Null, anstatt zu einer neuen Zeile. Auf diese Weise wird der Lesevorgang für 8 Zeichen fortgesetzt, auch wenn eines der früheren Zeichen eine neue Zeile ist (jedoch nicht, wenn es sich um eine Null handelt). Eine Alternative zu -n8 -d$'\0'ist die Verwendung von -N8, die genau 8 Zeichen liest oder bis das stdin EOF erreicht. Kein Trennzeichen wird berücksichtigt. Das wahrscheinlich passt besser auf Ihre Bedürfnisse, aber ich weiß nicht ohne Weiteres , wie viele Muscheln eine Lese haben, ehrt -Nim Gegensatz zu ehren -nund -d. Fahren Sie mit der Erklärung fort: -rsagt ignore \-escapes, so dass wir zum Beispiel \\als zwei Zeichen und nicht als ein einzelnes behandeln \.

Schließlich tun wir dies read ... <(command)nicht, command | read ...weil in der zweiten Form der Lesevorgang in einer Subshell ausgeführt wird, die dann sofort beendet wird und die gerade gelesenen Informationen verliert.

Eine andere Möglichkeit besteht darin, die gesamte Verarbeitung in der Subshell durchzuführen. Zum Beispiel:

$ echo abcdefghijklm | { read -n8 -d$'\0' -r; printf "REPLY=<%s>\n" "$REPLY"; }
REPLY=<abcdefgh>
zweifelhafter jim
quelle
1
Wenn Sie nur die 8 Zeichen ausgeben möchten und sie nicht in der Shell verarbeiten müssen, verwenden Sie einfach cut.
dubiousjim
Gut zu wissen read -n <num>; kleine Einschränkung: Bash 3.x (noch aktuell auf O) interpretiert fälschlicherweise <num>als Byte - Zählung und somit nicht mit Multi-Byte - Zeichen; Dies wurde in Bash 4.x behoben.
mklement0
Dies ist eine großartige und nützliche Antwort. Viel allgemeiner als die anderen.
not2qubit
2

Eine weitere einzeilige Lösung mit Parametererweiterung

echo ${word:0:x}

EG: word="Hello world"
echo ${word:0:3} or echo ${word::3} 
o/p: Hel


EG.2: word="Hello world"
echo ${word:1:3}
o/p: ell
Prabhat Kumar Singh
quelle
Sie können auch eine Variable verwenden, die die Länge enthält, z. B .: x=8; echo ${word:0:$x}Anstatt die ganze Zahl fest zu codieren.
Cometsong
1

Dies ist portabel:

a="$(command)"             # Get the output of the command.
b="????"                   # as many ? as characters are needed.
echo ${a%"${a#${b}}"}      # select that many chars from $a

Das Erstellen einer Zeichenfolge mit variabler Länge hat hier eine eigene Frage .

Gemeinschaft
quelle
0

Ich hatte dieses Problem beim manuellen Generieren von Prüfsummendateien im Maven-Repository. Leider cut -cwird am Ende der Ausgabe immer eine neue Zeile ausgegeben. Um das zu unterdrücken, benutze ich xxd:

command | xxd -l$BYTES | xxd -r

Es gibt genau $BYTESBytes aus, es sei denn, die commandAusgabe ist kürzer als die Ausgabe.

Krzysztof Jabłoński
quelle
Eine andere Methode, um die cutnachgestellte Newline zu entfernen, besteht darin, sie in | tr -d '\n'
Folgendes zu leiten