Заменить 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="foo"
someline
Base64Expression stringValue="bar"
Шаг за шагом:
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=""" }
/^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="foo"
someline
Base64Expression stringValue="bar"
при условии вашего echo | base64
это правильный подход.