Erhalte die ersten X Zeichen vom cat Befehl?

42

Ich habe eine Textdatei, die ich in eine Variable in meinem Shell-Skript ausgebe. Ich brauche aber nur die ersten 50 Zeichen.

Ich habe versucht, cat ${filename} cut -c1-50aber ich bekomme weit mehr als die ersten 50 Zeichen? Das kann daran liegen, dass Sie cutnach Zeilen suchen (nicht 100% sicher), während diese Textdatei eine lange Zeichenfolge sein kann - das hängt wirklich davon ab.

Gibt es ein Dienstprogramm, mit dem ich die ersten X-Zeichen eines catBefehls abrufen kann?

jkj2000
quelle
10
Hast du einen vergessen |? cat ${filename} | cut -c1-50
DisplayName
@DisplayName behoben, danke, dass du meinen Tippfehler abgefangen hast.
JKJ2000
1
@ jkj2000, ich habe auf die ältere Version zurückgegriffen, da dies die ursprüngliche Frage war.
Ramesh

Antworten:

61
head -c 50 file

Dies gibt die ersten 50 Bytes zurück.

Beachten Sie, dass der Befehl nicht immer auf allen Betriebssystemen gleich implementiert ist. Unter Linux und macOS verhält es sich so. Unter Solaris (11) müssen Sie die Gnu-Version in / usr / gnu / bin / verwenden.

Anzeigename
quelle
Kopf hat keine -cOption. Ich würde stattdessen für dd (1) gehen .
Mirabilos
7
Beachten Sie, dass diese Antwort davon ausgeht, dass die Datei nur ASCII-Zeichen enthält, da das OP nach den ersten X-Zeichen und nicht nach Bytes gefragt hat.
Calimo
2
@mirabilos Es ist möglicherweise nicht portabel, aber meine Version ( GNU coreutils 5.97).
Yossarian
1
POSIX wird jedoch nicht -cals gültige Option definiert , sodass dies definitiv von Ihrer lokalen Umgebung abhängt. unix.com/man-page/posix/1/head
Jules
1
@Calimo Ja, ich weiß, aber ich habe versucht, eine Textdatei mit 100 Zeichen zu erstellen, dann meinen Befehl ausgeführt und 50 Zeichen gedruckt. Aber Sie haben Recht mit ASCII, aber da OP dies als beantwortet kennzeichnete, gab es in seinem Fall keine.
DisplayName
27

Ihr cutBefehl funktioniert, wenn Sie eine Pipe verwenden, um Daten an diese zu übergeben:

cat ${file} | cut -c1-50 

Oder vermeiden Sie unnötigen Gebrauch von Katze und machen Sie sie ein bisschen sicherer:

cut -c1-50 < "$file"

Beachten Sie, dass die obigen Befehle die ersten 50 Zeichen (oder Bytes, abhängig von Ihrer cutImplementierung) jeder Eingabezeile ausgeben . Es sollte tun, was Sie erwarten, wenn Ihre Datei, wie Sie sagen, eine riesige Zeile ist.

terdon
quelle
8
dd status=none bs=1 count=50 if=${filename}

Dies gibt die ersten 50 Bytes zurück.

doneal24
quelle
dd hat keine status=noneflagge. Verwenden Sie 2>/dev/nullstattdessen (und zitieren Sie richtig): dd if="$filename" bs=1 count=50 2>/dev/null( bs=50 count=1Trotzdem sollten Sie in Betracht ziehen , die Anzahl der beteiligten Systemaufrufe zu verringern.)
Mirabilos
1
@mirabilos dd hat status=nonebei Verwendung von Ubuntu 14.04, Coreutils 8.21, aber 2>/dev/nullwenn Sie eine frühere Version verwenden , sind Sie richtig .
doneal24
1
@mirabilos Die meisten Linux-Distributionen verwenden GNU-Coreutils, ebenso wie FreeBSD und andere BSDs. Es ist unter Solaris als Paket gnu-coreutils verfügbar. Ja, dies ist "Unix & Linux" und sowohl Unix- als auch Linux-Systeme verwenden GNU-Coreutils.
doneal24
2
Nein, Unix-Systeme verwenden im Allgemeinen keine GNU-Dienstprogramme. GNU ist sogar eine Abkürzung für „GNU ist nicht Unix“. Bitte halten Sie sich an tragbare Lösungen, oder geben Sie dies an, wenn Sie nur GNU-Lösungen angeben müssen , und zeigen Sie, wenn möglich, eine gleichwertige tragbare Lösung an.
Mirabilos
1
Genau genommen macht das eines read()von 50 Bytes. Wenn filees sich beispielsweise um eine Pipe handelt und zu diesem Zeitpunkt weniger Zeichen verfügbar sind, werden weniger Bytes zurückgegeben. Um das Äquivalent von zu haben head -c50, müssten Sie GNU-spezifisch verwenden iflag=fullblock.
Stéphane Chazelas
4

Die meisten bisherigen Antworten gehen davon aus, dass 1 Byte = 1 Zeichen ist. Dies ist möglicherweise nicht der Fall, wenn Sie ein Nicht-ASCII-Gebietsschema verwenden.

Ein etwas robusterer Weg dies zu tun:

testString=$(head -c 200 < "${filename}") &&
  printf '%s\n' "${testString:0:50}"

Beachten Sie, dass dies voraussetzt:

  1. Sie verwenden ksh93, bash(oder einen aktuellen zshoder mksh(obwohl der einzige von mkshUTF-8 unterstützte Multibyte-Zeichensatz und nur danach set -o utf8-mode)) und eine Version head, die dies unterstützt -c(die meisten tun dies heutzutage, aber nicht unbedingt als Standard).
  2. Das aktuelle Gebietsschema wird auf die gleiche Codierung wie die Datei festgelegt (geben Sie ein locale charmapund file -- "$filename"überprüfen Sie dies). wenn nicht, setze es mit ie. LC_ALL=en_US.UTF-8)
  3. Ich habe die ersten 200 Bytes der Datei mit genommen head, wobei ich von UTF-8 im schlimmsten Fall ausgegangen bin , bei dem alle Zeichen mit höchstens 4 Bytes codiert sind. Dies sollte die meisten Fälle abdecken, die mir einfallen.
Calimo
quelle
Dies setzt natürlich auch GNU headoder eine andere Implementierung voraus , die die -cOption nōn-standard hinzufügt . Aber Sie benötigen bereits GNU-Bash. (Hinweis: mkshDer UTF-8-Modus kann dies für UTF-8-codierte Dateien tun.) Ich würde das OP fragen, ob Oktetts oder Multibyte-Zeichen erforderlich sind.
Mirabilos
Das setzt auch voraus, $filenameoder $testStringenthält keine leeren Zeilenumbrüche oder Platzhalter oder beginnt mit -.
Stéphane Chazelas
Das ${var:offset:length}Konstrukt, das Sie hier verwenden, stammt tatsächlich von ksh93und wird auch von neueren Versionen von zsh( zshhat ein eigenes $testString[1,50]) unterstützt. Du brauchst ${testString:0:50} in ksh93und zshaber.
Stéphane Chazelas
Habe
2
grep -om1 "^.\{50\}" ${filename}

Andere Variante (für die erste Zeile in der Datei)

(IFS= read -r line <${filename}; echo ${line:0:50})
Costas
quelle
Dies ist ein Missbrauch von Tools auf hoher Ebene - und es besteht die Gefahr, dass Sie nicht das tun, was Sie möchten, z. B. wenn sie das Gebietsschema kennen.
Mirabilos
@mirabilos Was meinst du mit High-Level-Tools : readund echo? Oder bash expansion?
Costas
grep(regexp), und ja, die Verwendung von Shell hier (Hinweis: Die erste Zeile kann groß sein). (Allerdings ist der Bashismus auch nicht in POSIX, aber die meisten Shells implementieren das.)
Mirabilos
0

1. Führen Sie für ASCII-Dateien die folgenden Schritte aus:

head -c 50 file.txt

Gibt beispielsweise die ersten 50 Zeichen der Datei file.txt aus.

2. Verwenden hexdumpSie für Binärdaten, um sie als Hexadezimalzeichen auszudrucken:

hexdump -n 50 -v file.bin

druckt beispielsweise die ersten 50 Bytes von file.bin aus.

Beachten Sie, dass ohne die -vOption verbose hexdumpwiederholte Zeilen durch ein Sternchen ( *) ersetzt werden. Siehe hier: https://superuser.com/questions/494245/what-does-an-asterisk-mean-in-hexdump-output/494613#494613 .

Gabriel Staples
quelle
-2

Hierfür können Sie sed verwenden, um das Problem schnell zu lösen

sed -e 's/^\(.\{50\}\).*/\1/' yourfile
munkeyoto
quelle
Neugierig zu wissen , wie das bekam , wenn er downvoted die Frage des OP löst: dies leistet „Ich habe nur die ersten 50 Zeichen müssen“ , was ohne UUOC (Useless Verwendung von Cat) angefordert wurde
munkeyoto
1
Diese Antwort gibt die ersten fünfzig Zeichen jeder Zeile in der Datei an, nicht nur die ersten 50 der Datei. Gibt auch überhaupt nichts aus, wenn alle Zeilen weniger als 50 Zeichen lang sind. Ihre Lösung würde besser funktionieren mitsed -n -e '1s/^\(.\{50\}\).*/\1/p' ${filename}
doneal24
Verstanden hätte nur: head -n 1 | sed -es / ^ (. \ {50 \}). * / \ 1 / '... und es hätte das Problem gelöst. OP erklärte: "brauchen nur die ersten 50 Zeichen"
Munkeyoto
1
Nee. Wenn die erste Zeile nur 49 Zeichen lang ist, wird nichts ausgegeben.
doneal24
Doug Ich verstand das das erste Mal, aber das OP erwähnte nichts über das Drucken, wenn die Zeile weniger als 50 Zeichen enthielt, also verstehe ich Ihren Punkt immer noch nicht, und der Punkt, an dem dies abgelehnt wurde, fiel wieder in das, womit es geklappt hätte head: head -n 1 $ {filename} | sed -n -e '1s / ^ (. \ {50 \}). * / \ 1 / p'
munkeyoto