Wil*_*ard 3 sed perl text-processing regular-expression
这是一个sed
特定的问题;我很清楚它可以用其他工具完成,但我正在努力扩展我的sed
.
如何使用sed
全局引用(实际上是反引号)脚本中未指定的单词?这个词被保存在保持空间中。
我想要的是这样的:
s/word/`&`/g
Run Code Online (Sandbox Code Playgroud)
但诀窍是,word
将不包含在 sed 脚本中,而是包含在保留空间中。所以它看起来更像是:
H
g
s/^\(.*\)\n\(.*\)\1\(.*\)$/\2`\1`\3/
Run Code Online (Sandbox Code Playgroud)
这将引用保留空间中保存的单词的一次出现。我想引用所有这些,但我不能只添加一个g
标志,因为它使用反向引用而不是静态正则表达式的方式。
H
g
s/^\(.*\)\n\(.*\)\1\(.*\)\1\(.*\)$/\2`\1`\3`\1`\4/
Run Code Online (Sandbox Code Playgroud)
这会处理单词的两次出现,但一次失败,并且忽略不止一次。
我想我可以使用一些干净简单的东西,比如:
s//`&`/g
Run Code Online (Sandbox Code Playgroud)
但这会重用上次使用的regex,而不是匹配的内容。(这是有道理的。)
有什么办法sed
可以做我想做的事吗?(实际上我很想知道这在 中有多容易perl
,但我仍然想看看如何在 中做到这一点sed
。)
更新
并不是说这个问题需要它,但我想我会提供更多关于我在提出这个问题时到底在做什么的背景:
我有一个很大的文档文本文件,其中的某些部分需要压缩并汇总到一个asciidoc
表格中。由于Description:
和Prototype:
行等,这很容易,所以我实际上编写了一个快速sed
脚本来为我完成所有解析。它工作得很好——但它缺少的一件事是我想对与该Description
行中列出的参数匹配的行中的单词进行反引号Prototype
。原型线看起来像这样:
Prototype: some_words_here(and, arg, list,here)
Run Code Online (Sandbox Code Playgroud)
有向上的200个不同的条目中我被输出表(和源文件包括比很多更多的文本),并且仅需要每个arglist中被用于反引号引号匹配的单词上的单个线。为了让事情变得更棘手,有些参数不在描述行中,有些在不止一次,有些参数是空的()。
然而,考虑到有时 arg 会匹配单词的一部分,我不想被反引号,有时 arg 名称是一个常用词(如from
),我只想在它被用于在解释该功能的使用的上下文中,自动化解决方案实际上根本不适合,而我过去常常vim
在一些棘手的宏的帮助下半手动完成这项工作。:)
那是一件很难的事。假设你有file
这样的:
$ cat file
word
line with a word and words and wording wordy words.
Run Code Online (Sandbox Code Playgroud)
在哪里:
`word`
。该sed
命令:
sed -n '1h; 2{x;G;:l;s/^\([^\n]\+\)\n\(.*[^`]\)\1\([^`]\)/\1\n\2`\1`\3/;tl;p}' file
Run Code Online (Sandbox Code Playgroud)
说明:
1h;
将第一行保存到保留空间(这是我们要搜索的等待)。
word
2{...}
适用于第二行。x;
交换模式空间和保持空间。G;
将保持空间附加到模式空间。在我们现在的模式空间中:$ cat file
word
line with a word and words and wording wordy words.
Run Code Online (Sandbox Code Playgroud)
:l;
设置一个称为l
点的标签供以后使用。s///
在上述模式空间中进行实际搜索/替换:
^\([^\n]\+\)\n
在“模式行”中搜索所有^
不是换行符[^\n]
(一次或多次\+
)的字符(从行首),直到换行符\n
。这现在存储在反向引用中\1
。它包含“模式线”。(.*[^`])
搜索任何.*
后跟一个字符的字符,它不是反引号[^`]
。这存储在\2
. \2
包含 now: line with a word and words and wording wordy
, 直到最后一次出现word
, 因为...\1
是下一个搜索词(反向引用\1
, word
),因此是“模式行”包含的内容。([^`])
这之后是另一个不是反引号的字符;保存以供参考\3
。如果我们不这样做(以及\2
上面的部分),我们将在无限循环中结束word
,一遍又一遍地引用相同的-> ````word````
,因为s///
总是会成功并tl;
跳回:l
(见下文tl;
)。\1\n\2\1
\3
以上所有内容都被反向引用所取代。第二个\1
是我们应该引用的(注意第一个引用是“模式线”)。tl;
如果s///
成功(我们替换了一些东西)跳转到被调用的标签l
并重新开始,直到没有更多的东西可以搜索和替换。当所有出现的单词都被替换/引用时,就是这种情况。p;
全部完成后,打印更改后的行(模式空间)。输出:
$ sed -n '1h; 2{x;G;:l;s/^\([^\n]\+\)\n\(.*[^`]\)\1\([^`]\)/\1\n\2`\1`\3/;tl;p}' file
word
line with a `word` and `word`s and `word`ing `word`y `word`s.
Run Code Online (Sandbox Code Playgroud)