bash: чтение из stdin до разделителя строки

bash: чтение из stdin до разделителя строки

Допустим, у меня есть два файла, содержащих произвольные байты: ./delimiterи ./data.

Я хочу прочитать данные ./dataдо первого вхождения последовательности байтов в файле ./delimiter.

Как это сделать с помощью Bash?

Пример:

  • Содержание./delimiter
    world
    
  • Содержание./data
    helloworld
    
  • Ожидаемый результат:
    hello
    

Похожий/эквивалентный вопрос:

Примечание: read -d delimне решает мою проблему, поскольку поддерживает только односимвольный разделитель, а не строку. Кроме того, он сохраняет результат в переменной, а переменные не поддерживают NULбайты. Я хочу вывод в stdout.

решение1

Perl спешит на помощь!

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

Специальная переменная$/устанавливает разделитель входных записей,местныйЕсли мы его используем, мы прочитаем весь файл (также называется "прихлебывание"). Затем мы используем оператор ромба для чтения из файла delimiterи устанавливаем разделитель на его содержимое. Затем мы считываем первую запись из dataфайла,чавкатьизвлекая из него разделитель записей.

решение2

С помощью zsh(единственной оболочки, которая может хранить произвольные последовательности байтов в своих переменных), предполагая, что dataи delimiterявляются обычными (или, по крайней мере, поддерживающими mmap()) файлами, вы можете сделать следующее:

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]*}

Или:

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]

(не ожидайте, что он будет очень эффективным или хорошо масштабируется для файлов размером более нескольких сотен мегабайт).

Чтобы распечатать эту часть дословно, используйте:

print -rn -- $firstpart

Или

printf %s $firstpart

Связанный контент