Linux-Befehl (wie cat) zum Lesen einer bestimmten Anzahl von Zeichen


120

Gibt es einen Befehl wie cat unter Linux, der eine bestimmte Anzahl von Zeichen aus einer Datei zurückgeben kann?

zB habe ich eine Textdatei wie:

Hello world
this is the second line
this is the third line

Und ich möchte etwas, das die ersten 5 Zeichen zurückgibt, was "Hallo" wäre.

Vielen Dank


Beachten Sie, dass keine der angegebenen Antworten nur N Bytes aus einem Stream verbraucht. Zum Beispiel: mkfifo /tmp/test.fifo; echo "hello world">/tmp/test.fifo & head -c 5 /tmp/test.fifoverbraucht auch, " world\n"was für immer verloren ist.
Yeti

Antworten:


192

head funktioniert auch:

head -c 100 file  # returns the first 100 bytes in the file

..wird die ersten 100 Bytes extrahieren und zurückgeben.

Das Schöne headdaran ist, dass die Syntax für tailÜbereinstimmungen:

tail -c 100 file  # returns the last 100 bytes in the file

Sie können diese kombinieren, um Bytebereiche zu erhalten. Um beispielsweise die zweiten 100 Bytes aus einer Datei abzurufen, lesen Sie die ersten 200 mit headund verwenden Sie tail, um die letzten 100 abzurufen:

head -c 200 file | tail -c 100

@Miffy: Lies die ersten 20 Bytes mit headund benutze dann tail, um die letzten 10 zu erhalten, zB:head -c 20 file | tail -c 10
Dan

47

Mit dd können Sie beliebige Byte-Blöcke extrahieren.

Beispielsweise,

dd skip=1234 count=5 bs=1

würde die Bytes 1235 bis 1239 von seiner Eingabe in ihre Ausgabe kopieren und den Rest verwerfen.

Gehen Sie folgendermaßen vor, um nur die ersten fünf Bytes von der Standardeingabe zu erhalten:

dd count=5 bs=1

Beachten Sie, dass dd, wenn Sie den Namen der Eingabedatei angeben möchten, über eine altmodische Argumentanalyse verfügt. Gehen Sie also folgendermaßen vor:

dd count=5 bs=1 if=filename

Beachten Sie auch, dass dd ausführlich verkündet, was es getan hat. Um dies wegzuwerfen, gehen Sie wie folgt vor:

dd count=5 bs=1 2>&-

oder

dd count=5 bs=1 2>/dev/null

2
Ich würde generell gegen diese Lösung empfehlen, da dd bs=1dd gezwungen ist, jeweils ein einzelnes Zeichen zu lesen und zu schreiben, was viel langsamer ist als headbei einer großen Anzahl. Bei count = 5 fällt dies jedoch nicht auf.
Ephemient

2
Was ist mit "dd count = 1 bs = 5"? Das hätte den Kopf fünf Bytes auf einmal gelesen. Dennoch ist Kopf wahrscheinlich eine klarere Lösung.
Ben Combee

1
Vielen Dank dafür - ich habe tatsächlich nach einer Möglichkeit gesucht, eine Binärdatei zu "schneiden", und ddanscheinend wird es den Trick tun. Prost!
Sdaau

Dies war ein Lebensretter auf Busybox ohne head -cImplementierung des dd bs=5 count=1Ansatzes funktioniert
Jay Paroline

11

Kopf :

Name

head - gibt den ersten Teil der Dateien aus

Zusammenfassung

Kopf [ OPTION ] ... [ DATEI ] ...

Beschreibung

Drucken Sie die ersten 10 Zeilen jeder DATEI in die Standardausgabe. Stellen Sie bei mehr als einer DATEI jeweils einen Header mit dem Dateinamen voran. Ohne DATEI oder wenn DATEI - ist, lesen Sie die Standardeingabe.

Obligatorische Argumente für lange Optionen sind auch für kurze Optionen obligatorisch.
-c , --bytes = [-] N gibt die ersten N Bytes jeder Datei aus; Drucken Sie mit dem führenden '-' alle bis auf die letzten N Bytes jeder Datei


3

Kopf oder Schwanz können es auch:

Kopf -c X.

Druckt die ersten X Bytes (nicht unbedingt Zeichen, wenn es sich um eine UTF-16-Datei handelt) der Datei. tail macht dasselbe, mit Ausnahme der letzten X Bytes.

Diese (und geschnitten) sind tragbar.


3
head -Line_number file_name | tail -1 |cut -c Num_of_chars

Dieses Skript gibt die genaue Anzahl der Zeichen aus der jeweiligen Zeile und Position an, z.

head -5 tst.txt | tail -1 |cut -c 5-8

gibt die Zeichen in Zeile 5 und die Zeichen 5 bis 8 von Zeile 5 an,

Hinweis : Mit tail -1dieser Option wird die letzte vom Kopf angezeigte Zeile ausgewählt.


2

Sie können die Linie auch herausgreifen und dann wie folgt ausschneiden:

grep 'text' Dateiname | schneide -c 1-5


Dies funktioniert nicht, wenn die Eingabedatei ein endloser Stream ohne \ n ist
Ajay Brahmakshatriya

2

Ich weiß, die Antwort ist eine Antwort auf eine Frage, die vor 6 Jahren gestellt wurde ...

Aber ich habe ein paar Stunden nach etwas Ähnlichem gesucht und dann herausgefunden, dass: cut -c genau das tut, mit einem zusätzlichen Bonus, dass Sie auch einen Offset angeben können.

cut -c 1-5 gibt Hallo zurück und cut -c 7-11 gibt world zurück . Kein anderer Befehl erforderlich


2
Ihr Recht!. Ich wollte nur die Möglichkeit eines allgemeineren Einzelbefehls hervorheben, der Text aus der Mitte einer Datei zurückgeben kann, im Gegensatz zu head -c liest nur die Startzeichen, tail -c die letzten Zeichen. Und ohne grep zu benutzen :).
Bobbyus

2

Obwohl dies vor Jahren beantwortet / akzeptiert wurde, ist die derzeit akzeptierte Antwort nur für Codierungen mit einem Byte pro Zeichen wie iso-8859-1 oder für Einzelbyte-Teilmengen von Zeichensätzen mit variablem Byte (wie lateinische Zeichen) korrekt innerhalb von UTF-8). Selbst die Verwendung von Mehrbyte-Spleißen würde immer noch nur für Fest-Multibyte-Codierungen wie UTF-16 funktionieren. Angesichts der Tatsache, dass UTF-8 jetzt auf dem besten Weg ist, ein universeller Standard zu werden, und wenn man sich diese Liste der Sprachen nach Anzahl der Muttersprachler und diese Liste der 30 besten Sprachen nach Muttersprache / Sekundärverwendung ansieht , ist es wichtig, auf a hinzuweisen einfache, zeichenfreundliche (nicht bytebasierte) Technik mit variablen Bytes unter Verwendung von cut -cund tr/sed mit Zeichenklassen.

Vergleichen Sie Folgendes, das aufgrund zweier häufiger lateinischer Fehler / Vermutungen in Bezug auf das Problem Bytes vs. Zeichen (eines ist headvs. cut, das andere ist [a-z][A-Z]vs. [:upper:][:lower:]) doppelt fehlschlägt :

$ printf 'Πού μπορώ να μάθω σανσκριτικά;\n' | \
$     head -c 1 | \
$     sed -e 's/[A-Z]/[a-z]/g'
[[unreadable binary mess, or nothing if the terminal filtered it]]

auf diese (Anmerkung: diese hat gut funktioniert auf FreeBSD, aber sowohl cut& trauf GNU / Linux noch griechischen verstümmelt in UTF-8 für mich aber):

$ printf 'Πού μπορώ να μάθω σανσκριτικά;\n' | \
$     cut -c 1 | \
$     tr '[:upper:]' '[:lower:]'
π

Eine andere neuere Antwort hatte bereits "Ausschneiden" vorgeschlagen, jedoch nur aufgrund des Nebenproblems, mit dem beliebige Offsets angegeben werden können, nicht aufgrund des direkt relevanten Problems zwischen Zeichen und Bytes.

Wenn Sie mit Variablen-Byte-Codierungen nicht richtig cutumgehen -c, können Sie für "die ersten XZeichen" (durch XIhre Nummer ersetzen ) Folgendes versuchen:

  • sed -E -e '1 s/^(.{X}).*$/\1/' -e q - was jedoch auf die erste Zeile beschränkt ist
  • head -n 1 | grep -E -o '^.{X}' - Dies ist auf die erste Zeile beschränkt und verkettet jedoch zwei Befehle
  • dd - was bereits in anderen Antworten vorgeschlagen wurde, aber wirklich umständlich ist
  • Ein kompliziertes sedSkript mit Schiebefensterpuffer zur Verarbeitung von Zeichen, die über mehrere Zeilen verteilt sind, aber das ist wahrscheinlich umständlicher / fragiler als nur die Verwendung von so etwasdd

Wenn Sie trZeichenklassen mit variablen Byte-Codierungen nicht korrekt verarbeiten, können Sie Folgendes versuchen:

  • sed -E -e 's/[[:upper:]]/\L&/g (GNU-spezifisch)

Entschuldigung, aber es funktioniert hier nicht ... gibt printf 'Πού ' | cut -c 1nur Kauderwelsch zurück ... es verhält sich wie 'Kopf'
LEo

Laut Online-Dokumentation ist es noch nicht verfügbar: "Wählen Sie zum Drucken nur die Zeichen an Positionen, die in der Zeichenliste aufgeführt sind. Das gleiche wie -b für den Moment, aber die Internationalisierung wird dies ändern." [ gnu.org/software/coreutils/manual/html_node/…
LEo

@LEo Basierend auf dem Link in Ihrem zweiten Kommentar scheint es, dass Sie ein GNU-basiertes Betriebssystem verwenden, vermutlich GNU / Linux. In diesem Fall wird dies erwartet - das erwähne ich am Ende meiner Antwort. Es funktionierte damals (und funktioniert jetzt) ​​für mich unter FreeBSD (und wahrscheinlich unter einigen anderen Betriebssystemen), funktionierte aber (und noch nicht) unter GNU / Linux. In diesem Fall erwähnte ich am Ende die alternativen Methoden. Ich persönlich kann es kaum erwarten, bis jemand die freie Zeit findet und freiwillig zur Verfügung stellt, um die Internationalisierung durchzuführen, die erforderlich ist, damit das GNU-Toolset funktioniert, sowie die anderen in dieser Hinsicht.
Rowanthorpe

0

Hier ist ein einfaches Skript, das mit dem abschließt dd hier genannten Ansatz abgeschlossen wird:

extract_chars.sh

#!/usr/bin/env bash

function show_help()
{
  IT="
extracts characters X to Y from stdin or FILE
usage: X Y {FILE}

e.g. 

2 10 /tmp/it     => extract chars 2-10 from /tmp/it
EOF
  "
  echo "$IT"
  exit
}

if [ "$1" == "help" ]
then
  show_help
fi
if [ -z "$1" ]
then
  show_help
fi

FROM=$1
TO=$2
COUNT=`expr $TO - $FROM + 1`

if [ -z "$3" ]
then
  dd skip=$FROM count=$COUNT bs=1 2>/dev/null
else
  dd skip=$FROM count=$COUNT bs=1 if=$3 2>/dev/null 
fi
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.