[英]Execute command defined by backreference in sed
我正在創建一個完全基於sed的原始實驗模板引擎(僅出於個人目的)。 我已經嘗試了好幾個小時了,現在要做的一件事是用它們包含的命令輸出替換某些文本模式。
為了澄清,如果輸入行看起來像這樣
Lorem {{echo ipsum}}
我將看到sed輸出看起來像這樣:
Lorem ipsum
我最接近的是:
echo 'Lorem {{echo ipsum}}' | sed 's/{{\(.*\)}}/'"$(\\1)"'/g'
這不起作用。
然而,
echo 'Lorem {{echo ipsum}}' | sed 's/{{\(.*\)}}/'"$(echo \\1)"'/g'
給我
Lorem echo ipsum
我不太了解這里發生了什么。 為什么我可以將后向引用賦予echo命令,但不能在$()中評估整個后向引用? \\\\ 1什么時候得到評估? 我嘗試使用純sed甚至可以實現的目標嗎?
請記住,對我來說,很清楚,使用其他工具可以輕松實現我要實現的目標。 但是,我對純sed是否可以實現這一點非常感興趣。
謝謝!
您的嘗試不起作用的原因是$()
在調用sed
之前已被外殼擴展。 因此,它不能使用sed
最終將要捕獲的反向引用。
使用GNU sed(而不是POSIX sed)可以做這種事情。 主要技巧是GNU sed在s
命令中帶有一個e
標志,使它用作為shell命令執行的模式空間的結果替換模式空間(整個空間)。 這意味着
echo 'echo foo' | sed 's/f/g/e'
打印goo
。
可以將其用於您的用例,如下所示:
echo 'Lorem {{echo ipsum}}' | sed ':a /\(.*\){{\(.*\)}}\(.*\)/ { h; s//\1\n\3/; x; s//\2/e; G; s/\(.*\)\n\(.*\)\n\(.*\)/\2\1\3/; ba }'
sed
代碼的工作方式如下:
:a # jump label for looping, in case there are
# several {{}} expressions in a line
/\(.*\){{\(.*\)}}\(.*\)/ { # if there is a {{}} expression,
h # make a copy of the line
s//\1\n\3/ # isolate the surrounding parts
x # swap the original back in
s//\2/e # isolate the command, execute, get output
G # get the outer parts we put into the hold
# buffer
s/\(.*\)\n\(.*\)\n\(.*\)/\2\1\3/ # rearrange the parts to put the command
# output into the right place
ba # rinse, repeat until all {{}} are covered
}
這利用了正則表達式中sed
的貪婪匹配來始終捕獲一行中的最后一個{{}}
表達式。 請注意,如果一行中有多個命令,而后一個命令具有多行輸出,則會遇到困難。 處理這種情況將需要定義一個標記,即不允許嵌入在數據中的命令作為其輸出的一部分,並且不允許包含模板。 我建議使用類似{{{}}}
,這將導致
sed ':a /\(.*\){{\(.*\)}}\(.*\)/ { h; s//{{{}}}\1{{{}}}\3/; x; s//\2/e; G; s/\(.*\)\n{{{}}}\(.*\){{{}}}\(.*\)/\2\1\3/; ba }'
其背后的原因是,如果嵌入式命令進一步打印{{}}
項,則模板引擎無論如何都會遇到麻煩。 不能強制執行此約定,但是無論如何,傳遞給此模板引擎的任何代碼最好都來自受信任的來源。
請注意,我不確定這整個事情是否是理智的想法1 。 您不打算在任何生產代碼中使用它,對嗎?
1但是,我很確定這是否是一個理智的想法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.