Декодирование base64 без учета скобок

Я пытаюсь декодировать файл, который в основном закодирован с помощью base64. Я хочу декодировать следующее, сохраняя при этом [_*_].

example.txt

wq9cXyjjg4QpXy/Crwo=
[_NOTBASE64ED_]
aGkgdGhlcmUK
[_CONSTANT_]
SGVsbG8gV29ybGQhCg==

Иногда это будет в такой форме

aGkgdGhlcmUK[_CONSTANT_]SGVsbG8gV29ybGQhCg==

Желаемый результат

¯\_(ツ)_/¯
[_NOTBASE64ED_]
hi there
[_CONSTANT_]
Hello World!
hi there[_CONSTANT_]Hello World!

Вывод ошибок

¯\_(ツ)_/¯
4��!:�@�H\�B�8ԓ��[��ܛBbase64: invalid input

Что я пробовал

base64 -di example.txt
base64 -d example.txt
base64 --wrap=0 -d -i example.txt

Я пробовал индивидуально использовать base64 для [_*_], используя grep -o. Затем найдите и
заменив их странным образом с массивами, но я не мог заставить его работать. base64ing все это, а затем декодирование. В результате получаются строки с двойным base64ed.

Размер файла значительно уменьшен! Кодируется с использованием base64 --wrap=0, цикла while и оператора if / else. [_*_] все еще должен быть там после декодирования.

Всегда ли блоки base64 представляют собой одну строку?

Barmar 10.11.2018 00:47

Не всегда, иногда вроде wq9cXyjjg4QpXy/Crwo=[_NOTBASE64ED_]aGkgdGhlcmUK

Caucasian Malaysian 10.11.2018 00:50

Чем это отличается от того, что вы разместили в примере?

Barmar 10.11.2018 00:51

Это пример, когда блоки base64 в одной строке разделены [_*_]. Если вы имеете в виду, что если один блок base64 очень длинный, он переходит на новую строку, или если два находятся на одной строке без разделителя, то нет.

Caucasian Malaysian 10.11.2018 00:54
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
4
394
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Вам нужен цикл, который читает каждую строку и проверяет, является ли она base64 или не-base64, и обрабатывает ее соответствующим образом.

while read -r line
do
    case "$line" in
        \[*\]) echo "$line" ;;
        *) base64 -d <<< "$line" ;;
    esac
done << example.txt

Кажется, он удаляет все, что было до [ в примере wq9cXyjjg4QpXy/Crwo=[_NOTBASE64ED_]aGkgdGhlcmUK (который я забыл добавить в исходный пост, теперь он добавлен). Также вы забыли ;; в конце *).

Caucasian Malaysian 10.11.2018 01:12

Я написал этот ответ до того, как вы добавили правку с [_NOTBASE64_] в середине строки.

Barmar 10.11.2018 01:59

Вероятно, это было бы проще на более мощном языке, таком как perl.

Barmar 10.11.2018 02:00
Ответ принят как подходящий

Я уверен, что у кого-то есть более умное решение, чем это. Но попробуйте это

#! /bin/bash

MYTMP1 = ""
function printInlineB64()
{
    local lines=($(echo $1 | sed -e 's/\[/\n[/g' -e 's/\]/]\n/g'))
    OUTPUT = ""
    for line in "${lines[@]}"; do
        MYTMP1=$(base64 -d <<< "$line" 2>/dev/null)
        if [ "$?" != "0" ]; then
            OUTPUT = "${OUTPUT}${line}"
        else
            OUTPUT = "${OUTPUT}${MYTMP1}"
        fi;
    done
    echo "$OUTPUT"
}

MYTMP2 = ""
function printB64Line()
{
    local line=$1

    # not fully base64 line
    if [[ ! "$line" =~ ^[A-Za-z0-9+/=]+$ ]]; then 
        printInlineB64 "$line"
        return
    fi;

    # likely base64 line
    MYTMP2=$(base64 -d <<< "$line" 2>/dev/null)
    if [ "$?" != "0" ]; then
        echo $line
    else
        echo $MYTMP2
    fi;
}


FILE=$1
if [ -z "$FILE" ]; then
    echo "Please give a file name in argument" 
    exit 1;
fi;

while read line; do
    printB64Line "$line"
done < ${FILE}

и вот вывод

$ cat example.txt && echo "========================= = " && ./base64.sh example.txt
wq9cXyjjg4QpXy/Crwo=
[_NOTBASE64ED_]
aGkgdGhlcmUK
[_CONSTANT_]
SGVsbG8gV29ybGQhCg==
==========================
¯\_(ツ)_/¯
[_NOTBASE64ED_]
hi there
[_CONSTANT_]
Hello World!

$ cat example2.txt && echo "========================= = " && ./base64.sh example2.txt
aGkgdGhlcmUK[_CONSTANT_]SGVsbG8gV29ybGQhCg==
==========================
hi there[_CONSTANT_]Hello World!

Я бы предложил использовать другие языки, кроме sh, но вот решение, использующее cut. Это подойдет для случая, когда в строке находится более одного [_constant_].

#!/bin/bash

function decode() {
    local data = ""
    local line=$1
    while [[ -n $line ]]; do
          data=$data$(echo $line | cut -d[ -f1 | base64 -d)
          const=$(echo $line | cut -d[ -sf2- | cut -d] -sf1)
          [[ -n $const ]] && data=$data[$const]
          line=$(echo $line | cut -d] -sf2-)
    done
    echo "$data"
}

while read -r line; do
    decode $line
done < example.txt

Если Perl - вариант, вы можете сказать что-то вроде:

perl -MMIME::Base64 -lpe '$_ = join("", grep {/^\[/ || chomp($_ = decode_base64($_)), 1} split(/(?=\[)|(?<=\])/))' example.txt

Приведенный ниже код эквивалентен приведенному выше, но для объяснения разбит на шаги:

#!/bin/bash

perl -MMIME::Base64 -lpe '
    @ary = split(/(?=\[)|(?<=\])/, $_);
    foreach (@ary) {
        if (! /^\[/) {
            chomp($_ = decode_base64($_));
        }
    }
    $_ = join("", @ary);
' example.txt
  • Опция -MMIME::Base64 загружает модуль кодека base64.
  • Опция -lpe заставляет Perl bahave, как AWK, перебирать строки ввода и неявно обрабатывать новые строки.
  • Регулярное выражение (?=\[)|(?<=\]) соответствует границе между блоком base64 и поддерживающим блоком, окруженным [...].
  • Функция split делит строку на блоки на границе и сохраняет их в массиве.
  • Затем переберите массив и декодируйте запись в кодировке base64, если она найдена.
  • Наконец, объедините блоки подстроки в строку для печати.

Другие вопросы по теме