El sed estándar no puede llamar a un shell ( GNU sed tiene una extensión para hacerlo , si solo le importa Linux no incrustado), por lo que tendrá que hacer parte del procesamiento fuera de sed. Hay varias soluciones; todo requiere una cita cuidadosa.
No está claro exactamente cómo desea que se expandan los valores. Por ejemplo, si una línea es
foo hello; echo $(true) 3
¿Cuál de los siguientes debe ser el resultado?
k=<foo> value=<hello; echo 3>
k=<foo> value=<hello; echo 3>
k=<foo> value=<hello; echo 3>
k=<foo> value=<foo hello
3>
Discutiré varias posibilidades a continuación.
cáscara pura
Puede hacer que el shell lea la entrada línea por línea y la procese. Esta es la solución más simple, y también la más rápida para archivos cortos. Esto es lo más cercano a su requerimiento "echo \2
":
while read -r keyword value; do
echo "k=<$keyword> v=<$(eval echo "$value")>"
done
read -r keyword value
se establece $keyword
en la primera palabra delimitada por espacios en blanco de la línea y $value
en el resto de la línea menos los espacios en blanco finales.
Si desea expandir referencias de variables, pero no ejecutar comandos fuera de las sustituciones de comandos, coloque $value
dentro de un documento aquí . Sospecho que esto es lo que realmente estabas buscando.
while read -r keyword value; do
echo "k=<$keyword> v=<$(cat <<EOF
$value
EOF
)>"
done
sed entubado en una concha
Puede transformar la entrada en un script de shell y evaluar eso. Sed está preparado para la tarea, aunque no es tan fácil. De acuerdo con su echo \2
requisito " " (tenga en cuenta que debemos escapar de las comillas simples en la palabra clave):
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
Al ir con un documento aquí, todavía necesitamos escapar de la palabra clave (pero de manera 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 es el método más rápido si tiene muchos datos: no inicia un proceso separado para cada línea.
awk
Las mismas técnicas que utilizamos con sed funcionan con awk. El programa resultante es considerablemente más legible. Yendo con " echo \2
":
awk '
1 {
kw = $1;
sub(/^ *[^ ]+ +/, "");
gsub(/\047/, "\047\\\047\047", $1);
print "echo \047k=<" kw ">\047 v=\\<" $0 "\\>";
}' | sh
Usando un documento aquí:
awk '
NR==1 { print "cat <<EOF" }
1 {
kw = $1;
sub(/^ *[^ ]+ +/, "");
gsub(/\\\$`/, "\\&", $1);
print "k=<" kw "> v=<" $0 ">";
}
END { print "EOF" }
' | sh