Заменить Sed на вывод команды bash, используя в качестве аргумента группу перехвата

Я пытаюсь сделать замену base64 с помощью sed.

То, что я пытаюсь сделать, это:

sed -i "s|\(some\)\(pattern\)|\1 $(echo "\2" | base64 -d)|g" myFile

На английском это будет:

  • Математический образец
  • Захват групп
  • Используйте захваченную группу в команде bash
  • Используйте вывод этой команды в качестве строки замены

Пока моя команда не работает с \2 известен только sed, а не команде bash, которую я вызываю.

Какое элегантное решение я должен передать группе захвата в команду, которую я хочу использовать вывод?


редактировать

Вот минимальный пример того, что я пытаюсь сделать:

У меня есть следующий файл:

someline
someline
Base64Expression stringValue="Zm9v"
someline
Base64Expression stringValue="YmFy"

И я хочу заменить base64 обычным текстом:

someline
someline
Base64Expression stringValue="foo"
someline
Base64Expression stringValue="bar"

В будущем мне придется выполнить обратную операцию (кодирование строки в base64 в декодированном файле)

Я начал использовать awk, но я подумал, что с sed это может быть проще (и намного элегантнее). Пока что с awk у меня есть это (где $bundle это файл, который я редактирую):

#For each line containing "Base64Expression"
#Put in the array $substitutions[]:
# The number of the line (NR)
# The encoded expression ($2)
# The decoded expression (x)
substitutions=($(awk -v bd=$bundle '
    BEGIN {
        # Change the separator from default
        FS="""
        ORS=","
        OFS=","
    }
    /Base64Expression/ {
        #Decode the base64 lines
        cmd="echo -ne \""$2"\" | base64 -d"
        cmd | getline x

        if ( (cmd | getline) == 0 ){
            print NR, $2, x
        }
    }
' $bundle))

# Substitute the encoded expressions by the decoded ones
# Use the entries of the array 3 by 3
# Create a sed command which takes the lines numbers
for ((i=0; i<${#substitutions[@]}; i+=3))
do
    # Do the substitution only if the string is not empty
    # Allows to handle properly the empty variables
    if [ ${substitutions[$((i+1))]} ]
    then
        sed -i -e "${substitutions[$i]}s#${substitutions[$((i+1))]}#${substitutions[$((i+2))]}#" $bundle
    fi
done

2 ответа

Решение

Ты можешь использовать e в GNU sed передать строку подстановки в оболочку для оценки. Таким образом, вы можете сказать:

printf "%s %s" "something" "\1"

куда \1 держит захваченную группу. Все вместе:

$ sed -r 's#match_([0-9]*).*#printf "%s %s" "something" "\1"#e' <<< "match_555 hello"
something 555

Это удобно, когда вы хотите выполнить какое-либо действие с захваченной группой, как в этом случае.

Итак, давайте захватим первую часть строки, затем ту часть, которая должна быть закодирована, и, наконец, остальную часть. Как только это будет сделано, давайте напечатаем эти части обратно printf вызывая использование base64 -d против второго среза:

$ sed -r '/^Base64/s#(.*;)([^\&]*)(&.*)# printf "%s%s%s" "\1" $(echo "\2" | base64 -d) "\3";#e' file
someline
someline
Base64Expression stringValue=&quot;foo&quot;
someline
Base64Expression stringValue=&quot;bar&quot;

Шаг за шагом:

sed -r '/^Base64/s#(.*;)([^\&]*)(&.*)# printf "%s%s%s" "\1" $(echo "\2" | base64 -d) "\3";#e' file
#        ^^^^^^^    ^^^  ^^^^^^  ^^^                        ^^^^^^^^^^^^^^^^^^^^^^^^       ^
#           |   first part  |   the rest                encode the 2nd captured group      |
#           |               |                                                              |
#           |           important part                                      execute the command
#           |
# on lines starting with Base64, do...

Идея исходит из этого превосходного ответа от anubhava " Как изменить формат даты в sed?".,

Похоже, это то, что вы пытаетесь сделать:

$ cat tst.awk
BEGIN { FS=OFS="&quot;" }
/^Base64Expression/ {
    cmd="echo -ne \""$2"\" | base64 -d"
    if ( (cmd | getline x) > 0 ) {
        $2 = x
    }
    close(cmd)
}
{ print }

$ awk -f tst.awk file
someline
someline
Base64Expression stringValue=&quot;foo&quot;
someline
Base64Expression stringValue=&quot;bar&quot;

при условии вашего echo | base64 это правильный подход.

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