bash: Von stdin lesen, bis ein String-Trennzeichen kommt

bash: Von stdin lesen, bis ein String-Trennzeichen kommt

Nehmen wir an, ich habe zwei Dateien mit beliebigen Bytes: ./delimiterund ./data.

Ich möchte ./databis zum ersten Vorkommen der Bytefolge in lesen (ausschließlich) ./delimiter.

Wie würde ich dies mit Bash machen?

Beispiel:

  • Inhalt von./delimiter
    world
    
  • Inhalt von./data
    helloworld
    
  • Erwartetes Ergebnis:
    hello
    

Ähnliche/gleichwertige Frage:

Hinweis: read -d delimlöst mein Problem nicht, da nur ein einstelliges Trennzeichen und kein String unterstützt wird. Außerdem speichert es das Ergebnis in einer Variablen, und Variablen unterstützen keine NULBytes. Ich möchte die Ausgabe auf stdout.

Antwort1

Perl zur Rettung!

perl -e 'local $/;
         open $de, "<", "delimiter" or die $!;
         $/ = <$de>;
         open $da, "<", "data" or die $!;
         chomp( $first = <$da> );
         print $first;'

Die spezielle Variable$/setzt den Eingabedatensatz-Trennzeichen, indemlokalWenn wir es tun, lesen wir die ganze Datei (auch "slurping" genannt). Dann verwenden wir den Rautenoperator, um aus der delimiterDatei zu lesen, und setzen den Trenner auf den Inhalt. Dann lesen wir den ersten Datensatz aus der dataDatei,mampfenEntfernen Sie daraus den Datensatztrenner.

Antwort2

Mit zsh(der einzigen Shell, die beliebige Bytefolgen in ihren Variablen speichern kann) können Sie unter der Annahme, dass es sich bei dataund delimiterum reguläre (oder zumindest mmap()-fähige) Dateien handelt, Folgendes tun:

zmodload zsh/mapfile

set +o multibyte # necessary so sequences of bytes that
                 # happen to form valid characters may be
                 # broken in the middle if necessary.

firstpart=${mapfile[data]%%$mapfile[delimiter]*}

Oder:

zmodload zsh/mapfile
set +o multibyte # necessary so sequences of bytes that
                 # happen to form valid characters may be
                 # broken in the middle if necessary.

delimiter=$mapfile[delimiter]
parts=( ${(ps[$delimiter])mapfile[data]} )

firstpart=$parts[1]

(erwarten Sie nicht, dass es sehr effizient ist oder sich gut auf Dateien skalieren lässt, die größer als ein paar Hundert Megabyte sind).

Um diesen Teil wörtlich auszudrucken, verwenden Sie:

print -rn -- $firstpart

Oder

printf %s $firstpart

verwandte Informationen