O sed padrão não pode chamar um shell (o GNU sed tem uma extensão para fazê-lo , se você se importa apenas com o Linux não incorporado), então você terá que fazer parte do processamento fora do sed. Existem várias soluções; todos requerem citações cuidadosas.
Não está claro exatamente como você deseja que os valores sejam expandidos. Por exemplo, se uma linha é
foo hello; echo $(true) 3
Qual das seguintes opções deve ser a saída?
k=<foo> value=<hello; echo 3>
k=<foo> value=<hello; echo 3>
k=<foo> value=<hello; echo 3>
k=<foo> value=<foo hello
3>
Vou discutir várias possibilidades abaixo.
casca pura
Você pode fazer com que o shell leia a entrada de linha por linha e processe-a. Esta é a solução mais simples e também a mais rápida para arquivos curtos. Esta é a coisa mais próxima do seu requisito " echo \2
":
while read -r keyword value; do
echo "k=<$keyword> v=<$(eval echo "$value")>"
done
read -r keyword value
define $keyword
a primeira palavra da linha delimitada por espaços em branco e $value
o restante da linha menos o espaço em branco à direita.
Se você deseja expandir referências de variáveis, mas não executar comandos fora das substituições de comandos, coloque $value
dentro de um documento aqui . Eu suspeito que isso é o que você realmente estava procurando.
while read -r keyword value; do
echo "k=<$keyword> v=<$(cat <<EOF
$value
EOF
)>"
done
sed canalizado em uma concha
Você pode transformar a entrada em um script de shell e avaliar isso. Sed está à altura da tarefa, embora não seja tão fácil. Seguindo o seu echo \2
requisito " " (observe que precisamos escapar de aspas simples na palavra-chave):
sed -e 's/^ *//' -e 'h' \
-e 's/[^ ]* *//' -e 'x' \
-e 's/ .*//' -e "s/'/'\\\\''/g" -e "s/^/echo 'k=</" \
-e 'G' -e "s/\n/>' v=\\</" -e 's/$/\\>/' | sh
Indo com um documento aqui, ainda precisamos escapar da palavra-chave (mas de forma diferente).
{
echo 'cat <<EOF'
sed -e 's/^ */k=</' -e 'h' \
-e 's/[^ ]* *//' -e 'x' -e 's/ .*//' -e 's/[\$`]/\\&/g' \
-e 'G' -e "s/\n/> v=</" -e 's/$/>/'
echo 'EOF'
} | sh
Este é o método mais rápido se você tiver muitos dados: ele não inicia um processo separado para cada linha.
awk
As mesmas técnicas que usamos no sed trabalham com o awk. O programa resultante é consideravelmente mais legível. Indo com " echo \2
":
awk '
1 {
kw = $1;
sub(/^ *[^ ]+ +/, "");
gsub(/\047/, "\047\\\047\047", $1);
print "echo \047k=<" kw ">\047 v=\\<" $0 "\\>";
}' | sh
Usando um documento aqui:
awk '
NR==1 { print "cat <<EOF" }
1 {
kw = $1;
sub(/^ *[^ ]+ +/, "");
gsub(/\\\$`/, "\\&", $1);
print "k=<" kw "> v=<" $0 ">";
}
END { print "EOF" }
' | sh