Захват специальных символов из стандартного ввода в переменную оболочки - PullRequest
1 голос
/ 20 апреля 2020

У меня есть программа, которая печатает что-то, что содержит нулевые байты \0 и специальные символы, такие как \x1f и символы новой строки. Например:

someprogram

#!/bin/bash
printf "ALICE\0BOB\x1fCHARLIE\n"

Учитывая такую ​​программу, я хочу прочитать ее вывод таким образом, чтобы все эти специальные символы были захвачены в переменной оболочки output , Так что, если я запущу:

echo $output

, потому что я не даю -e, я бы хотел, чтобы результат был:

ALICE\0BOB\x1fCHARLIE\n

Как этого достичь?

Моя первая попытка была:

output=$(someprogram)

Но я получил этот отраженный вывод, который не имеет специальных символов:

./myscript.sh: line 2: warning: command substitution: ignored null byte in input
ALICEBOBCHARLIE

Я также пытался использовать read следующим образом:

output=""
while read -r
do
    output="$output$REPLY"
done < <(someprogram)

Затем я избавился от предупреждения, но в выводе все еще отсутствуют все специальные символы:

ALICEBOBCHARLIE

Так как я могу захватить вывод someprogram таким образом, чтобы у меня были все специальные символы в моей результирующей строке?

РЕДАКТИРОВАТЬ: Обратите внимание, что такие строки можно иметь в bash:

$ x="ALICE\0BOB\x1fCHARLIE\n"
$ echo $x
ALICE\0BOB\x1fCHARLIE\n

Так что Это не проблема.

РЕДАКТИРОВАТЬ 2: Я переформулирую вопрос немного теперь, когда я получил принятый ответ, и я понял вещи немного лучше. Итак, мне просто нужно было сохранить выходные данные someprogram в некоторой переменной оболочки таким образом, чтобы я мог распечатать его на стандартный вывод без каких-либо изменений каких-либо специальных символов, как если бы someprogram был просто передан напрямую на стандартный вывод.

1 Ответ

1 голос
/ 20 апреля 2020

Вы просто не можете хранить нулевой байт в bash переменных. Это невозможно.

Обычное решение - преобразовать поток байтов в шестнадцатеричный. Затем конвертируйте его обратно каждый раз, когда вы хотите что-то с ним сделать.

$ x=$(printf "ALICE\0BOB\x1fCHARLIE\n" | xxd -p)
$ echo "$x"
414c49434500424f421f434841524c49450a
$ <<<"$x" xxd -p -r | hexdump -C
00000000  41 4c 49 43 45 00 42 4f  42 1f 43 48 41 52 4c 49  |ALICE.BOB.CHARLI|
00000010  45 0a                                             |E.|
00000012

Вы также можете написать свои собственные функции сериализации и десериализации для этой цели.

Еще одна идея, которую я имею для Пример чтения данных в массив с использованием нулевого байта в качестве разделителя (так как любой другой байт допустим). Это, однако, будет иметь проблемы с распознаванием завершающего нулевого байта:

 $ readarray -d '' arr < <(printf "ALICE\0BOB\x1fCHARLIE\n")
 $ printf "%s\0" "${arr[@]}" | hexdump -C
 00000000  41 4c 49 43 45 00 42 4f  42 1f 43 48 41 52 4c 49   |ALICE.BOB.CHARLI|
 00000010  45 0a 00                                          |E..|
 #               ^^ additional zero byte if input doesn't contain a trailing zero byte
 00000013
...