Sed standard non può chiamare una shell ( GNU sed ha un'estensione per farlo , se ti interessa solo Linux non incorporato), quindi dovrai fare un po 'dell'elaborazione al di fuori di sed. Esistono diverse soluzioni; tutti richiedono un preventivo accurato.
Non è chiaro esattamente come si desidera espandere i valori. Ad esempio, se una linea è
foo hello; echo $(true) 3
quale dei seguenti dovrebbe essere l'output?
k=<foo> value=<hello; echo 3>
k=<foo> value=<hello; echo 3>
k=<foo> value=<hello; echo 3>
k=<foo> value=<foo hello
3>
Discuterò diverse possibilità di seguito.
guscio puro
È possibile ottenere la shell per leggere l'input riga per riga ed elaborarlo. Questa è la soluzione più semplice e anche la più veloce per i file brevi. Questa è la cosa più vicina alle tue esigenze " echo \2
":
while read -r keyword value; do
echo "k=<$keyword> v=<$(eval echo "$value")>"
done
read -r keyword value
imposta $keyword
sulla prima parola delimitata da spazi bianchi della riga e $value
sul resto della riga meno lo spazio bianco finale.
Se si desidera espandere i riferimenti alle variabili, ma non eseguire comandi al di fuori delle sostituzioni di comandi, inserire $value
un documento qui . Ho il sospetto che questo è quello che stavi davvero cercando.
while read -r keyword value; do
echo "k=<$keyword> v=<$(cat <<EOF
$value
EOF
)>"
done
sed convogliato in un guscio
È possibile trasformare l'input in uno script di shell e valutarlo. Sed è all'altezza del compito, anche se non è così facile. In linea con il tuo echo \2
requisito " " (nota che dobbiamo evitare le virgolette singole nella parola chiave):
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
Andando con un documento qui, dobbiamo ancora sfuggire alla parola chiave (ma in modo diverso).
{
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
Questo è il metodo più veloce se hai molti dati: non avvia un processo separato per ogni linea.
awk
Le stesse tecniche che abbiamo usato con sed funzionano con awk. Il programma risultante è notevolmente più leggibile. Andando con " echo \2
":
awk '
1 {
kw = $1;
sub(/^ *[^ ]+ +/, "");
gsub(/\047/, "\047\\\047\047", $1);
print "echo \047k=<" kw ">\047 v=\\<" $0 "\\>";
}' | sh
Utilizzando un documento qui:
awk '
NR==1 { print "cat <<EOF" }
1 {
kw = $1;
sub(/^ *[^ ]+ +/, "");
gsub(/\\\$`/, "\\&", $1);
print "k=<" kw "> v=<" $0 ">";
}
END { print "EOF" }
' | sh