Стандартный sed не может вызывать оболочку ( GNU sed имеет расширение для этого) , если вы заботитесь только о не встроенном Linux), поэтому вам придется выполнять некоторую обработку вне sed. Есть несколько решений; все требуют тщательного цитирования.
Непонятно, как именно вы хотите, чтобы значения были расширены. Например, если строка
foo hello; echo $(true) 3
какой из следующих выводов должен быть?
k=<foo> value=<hello; echo 3>
k=<foo> value=<hello; echo 3>
k=<foo> value=<hello; echo 3>
k=<foo> value=<foo hello
3>
Я расскажу о нескольких возможностях ниже.
чистая оболочка
Вы можете заставить оболочку читать строку ввода построчно и обрабатывать ее. Это самое простое решение, а также самое быстрое для коротких файлов. Это самое близкое к вашему требованию « echo \2»:
while read -r keyword value; do
echo "k=<$keyword> v=<$(eval echo "$value")>"
done
read -r keyword valueзадает $keywordпервое разделенное пробелами слово строки, а $valueостальной части строки минус конечный пробел.
Если вы хотите расширить ссылки на переменные, но не выполнять команды вне подстановок команд, поместите их $valueв документ здесь . Я подозреваю, что это то, что вы действительно искали.
while read -r keyword value; do
echo "k=<$keyword> v=<$(cat <<EOF
$value
EOF
)>"
done
седь по трубам
Вы можете преобразовать ввод в сценарий оболочки и оценить его. Сед справляется с задачей, хотя это не так просто. Следуя вашему echo \2требованию « » (обратите внимание, что нам нужно избегать одинарных кавычек в ключевом слове):
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
Переходя к документу здесь, нам все еще нужно экранировать ключевое слово (но по-другому).
{
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
Это самый быстрый метод, если у вас много данных: он не запускает отдельный процесс для каждой строки.
AWK
Те же самые методы, которые мы использовали с sed, работают с awk. Полученная программа значительно более читабельна. Идем с « echo \2»:
awk '
1 {
kw = $1;
sub(/^ *[^ ]+ +/, "");
gsub(/\047/, "\047\\\047\047", $1);
print "echo \047k=<" kw ">\047 v=\\<" $0 "\\>";
}' | sh
Используя здесь документ:
awk '
NR==1 { print "cat <<EOF" }
1 {
kw = $1;
sub(/^ *[^ ]+ +/, "");
gsub(/\\\$`/, "\\&", $1);
print "k=<" kw "> v=<" $0 ">";
}
END { print "EOF" }
' | sh