Вопрос или проблема
Я хочу выполнить кодирование в Base64 с помощью команды
echo -en "my_message" | openssl sha1 -hmac "secret_key" | base64
Выходная строка команды openssl
соответствует ожиданиям, но результат base64
не такой, как вывод с openssl
, так как в нем есть символ новой строки. Если я выполняю команду
echo -en "my_message" | openssl sha1 -hmac "secret_key" | xargs echo -n | base64
То конечный вывод правильный.
Мне интересно, есть ли более элегантный способ выполнения этой команды
openssl sha1 -hmac "secret_key"
выводит такую строку текста:
SHA1(stdin)= 5238cc013426063a31b5db127f9c939f9218e1f3
Он не только добавляет символ новой строки (если бы его не было, это было бы недопустимым текстом!), но и выводит результат в шестнадцатеричном коде вместо base64, с префиксом SHA1(stdin)=
.
Если вам нужен дайджест в формате base64, используйте:
openssl sha1 -binary -hmac "secret_key"
Где он будет выведен в сыром виде, который вы можете передать в xxd -p
для шестнадцатеречного кодирования или в base64
, чтобы получить кодирование в base64.
Что касается более общего вопроса о удалении символов новой строки:
- Передача в
tr -d '\n'
удалит все символы новой строки. - Передача в
head -c -1
удалит последний байт (независимо от того, является ли он новой строкой или нет). - Передача в
perl -pe 's/\n\z// if eof'
удалит последний байт вывода, если это символ новой строки.
Передача в xargs echo -n
является неверной в общем случае, так как
- Как
xargs
, так иecho
могут искажать данные.xargs
определенно не является инструментом для обработки текста. - Не все
echo
поддерживают-n
, те, которые не поддерживают опции, обычно обрабатывают экранирование\
.xargs printf %s
было бы лучше. - Это вызовет внешнюю утилиту
echo
, так что аргументы будут отображаться в выводеps
, что обычно является общедоступной информацией.
cmd_output=$(cmd)
printf %s "$cmd_output"
Удалит все завершающие символы новой строки, но, за исключением zsh
, также не сможет обработать нулевые байты, что делает его неприемлемым, например, для сырого двоичного дайджеста (хотя нет смысла удалять завершающие переводы строк (байты 0x0A) из двоичного дайджеста).
Ответ или решение
Чтобы получить корректную кодировку Base64 без ненужных символов новой строки, вы можете воспользоваться параметром -binary
при вызове команды OpenSSL, как вы уже упомянули. Это позволит получить бинарный вывод SHA1-хэширования без дополнительных префиксов и символов новой строки.
Вот как может выглядеть ваша команда:
echo -en "my_message" | openssl sha1 -binary -hmac "secret_key" | base64
Когда вы используете -binary
, OpenSSL выводит двоичный результат, и последующая команда base64
корректно закодирует его в Base64 без добавления лишних символов.
Если вам необходимо удалить новые строки для других случаев, вы можете использовать несколько подходов:
- tr для удаления всех символов новой строки:
your_command | tr -d '\n'
- head для удаления последнего символа:
your_command | head -c -1
- perl для удаления последнего символа, если он является новой строкой:
your_command | perl -pe 's/\n\z// if eof'
Тем не менее, методы с использованием xargs
и echo
не рекомендуется использовать в общем случае, так как они могут исказить данные:
xargs
не предназначен для обработки текста и может вводить нежелательные пробелы или изменять форматирование.echo
может вести себя по-разному в зависимости от системы и реализации, что делает его ненадежным для обработки данных.
Для более безопасного подхода вы можете использовать printf
, чтобы избежать проблем с echo
:
your_command | xargs printf "%s"
Однако, как вы отметили, cmd_output=$(cmd)
и printf %s "$cmd_output"
— это способ удаления всех завершающих символов новой строки, но, за исключением zsh
, это не обрабатывает нулевые байты, поэтому будьте осторожны с использованием этого метода для бинарных данных.
Таким образом, для вашей задачи с кодировкой в Base64 рекомендуется использовать вариант с openssl sha1 -binary
, как это указано в первом примере. Это решение является наиболее элегантным и эффективным для вашей ситуации.