在文本文件中同一字符串的开头用 $ 符号替换任何 闭合字符串

在文本文件中同一字符串的开头用 $ 符号替换任何  闭合字符串

我有一些文件驻留在 Linux 系统上,其中包含一些占位符,例如下面的文件:

测试.txt:

This is a line with <VARIABLE1>@<VARIABLE2>.
This is a line with <VARIABLE3>.
This is a line with <VARIABLE_UNKNOWN>.
This is another line contains a<b.

我想更改此文件,如下所示:

This is a test line with $VARIABLE1@$VARIABLE2.
This is a test line with $VARIABLE3.
This is a test line with $VARIABLE_UNKNOWN.
This is another line contains a<b.

请注意,所有这些以 结尾的变量<>仅包含大写字母、数字和下划线。

我本可以使用以下方法,但a<b变成了a$b

file_contents=$(<$file_path)
file_contents=${file_contents//</$}
file_contents=$(echo "$file_contents" | tr -d '>')
echo "$file_contents" > test.txt

我试图避免sed使用变得非常难以调试的复杂命令。我怎样才能实现这个目标?

答案1

由于这是对各行的简单替换,因此执行此操作的 sed 命令并不复杂:

$ sed -E 's/<([[:upper:][:digit:]_]+)>/$\1/g' file
This is a line with $VARIABLE1@$VARIABLE2.
This is a line with $VARIABLE3.
This is a line with $VARIABLE_UNKNOWN.
This is another line contains a<b.

或者如果您的 sed 没有-E任何 POSIX sed:

sed 's/<\([[:upper:][:digit:]_]\{1,\}\)>/$\1/g' file

如果您的 sed 甚至不兼容 POSIX 那么买一个新的但对于这个特定的事情你可能会做:

sed 's/<\([A-Z0-9_][A-Z0-9_]*\)>/$\1/g' file

作为@chrisdavies 指出,但这可能不是您真正应该尝试获得的输出,因为它会变成<VAR1>27$VAR127您应该真正瞄准其中任何一个:

$ sed -E 's/<([[:alnum:]_]+)>/${\1}/g' file
This is a line with ${VARIABLE1}@${VARIABLE2}.
This is a line with ${VARIABLE3}.
This is a line with ${VARIABLE_UNKNOWN}.
This is another line contains a<b.

$ sed -E 's/<([[:alnum:]_]+)>/"${\1}"/g' file
This is a line with "${VARIABLE1}"@"${VARIABLE2}".
This is a line with "${VARIABLE3}".
This is a line with "${VARIABLE_UNKNOWN}".
This is another line contains a<b.

取决于您计划如何处理该输出。

FWIW 通常,当人们在文本中有占位符字符串时,他们不会将其替换为名字shell 变量,他们将它们替换为内容shell 变量,因为否则当您可以首先使用 shell 变量名称创建文本时,在文本中使用占位符有什么意义呢?

答案2

如果问题可以表述为“我想转换所有包含在其中< >且仅由一个或多个大写字母、数字和下划线组成的字符串,这些字符串包含在< >它们自身中,但用 a$代替< >”,那么您可以这样做:

$ perl -pe 's/<([A-Z\d_]+)>/\$$1/g' file 
This is a line with $VARIABLE1@$VARIABLE2.
This is a line with $VARIABLE3.
This is a line with $VARIABLE_UNKNOWN.
This is another line contains a<b.

-pe意味着“逐行读取输入文件,应用给出的脚本-e,然后打印每一行”。然后,我们将替换运算符 ( s/OLD/NEW/) 与g标志一起使用,以便它替换该行中的所有匹配项。最后,正则表达式查找<后跟一个或多个(+指一个或多个)大写 ASCII 字母 ( A-Z)、ASCII1 十进制数字 ( \d) 或_以 结尾的下划线 ( ) >。现在,因为模式位于括号 ( ) 中,所以我们已“捕获”它并可以在替换中([A-Z\d_]+)引用它。$1因此,我们将匹配的内容替换为 a $(需要转义为\$),然后替换匹配的内容:\$$1


至少只要$PERL_UNICODE未设置环境变量,在这种情况下它就可以匹配其他类型的十进制数字。使用该a标志给s///操作符保证只有0123456789被匹配,或者替换\d0-9or0123456789

答案3

使用(以前称为 Perl_6)

~$ raku -pe 's:g/ \< ( <[A..Z0..9_]>+ ) \> /\$$0/;'  file

再说一遍,这几乎是 @terdon 优秀 Perl 答案的直接翻译。

在乐,

  1. 正则表达式修饰符(例如global)位于匹配器的头部,前面带有冒号,以提供s:g///“替代全局”形式。
  2. <[ ... ]>在识别域内,使用尖括号包围的方括号创建自定义字符类。方括号单独用于将正则表达式原子和/或属性分组在一起(参见底部的示例)。
  3. 字符范围用..双点指定,如 (例如)A..Z0..9
  4. Raku 简化了转义规则,使得所有非字母数字非下划线字符必须加引号或(反斜杠)转义才能被理解为正则表达式中的文字,因此需要在识别域中使用\<and 。\>
  5. 编号捕获在 Raku 中通过括号指定(与 Perl 中相同),但是这些编号捕获从替换域开始$0并且必须在替换域中使用。
  6. OP 指的是错误的替换,并且通常要求反斜杠某些字符可能会出现问题。为了提供帮助,Raku 允许{...}在替换域中使用代码块,以便可以编写上述替换{"\$$0"}(即内插字符串)。对于在输出中执行简单的数学运算(求和等)非常有用。

输入示例:

This is a line with <VARIABLE1>@<VARIABLE2>.
This is a line with <VARIABLE3>.
This is a line with <VARIABLE_UNKNOWN>.
This is another line contains a<b.

示例输出:

This is a line with $VARIABLE1@$VARIABLE2.
This is a line with $VARIABLE3.
This is a line with $VARIABLE_UNKNOWN.
This is another line contains a<b.

最后,@terdon 很好地概述了所有正则表达式系统的问题,以便需要准确理解数字,即这些是 ASCII 数字还是 Unicode 数字?

Raku 以其成为“Unicode 就绪”语言而自豪,您可以在底部的第一个链接中找到用于 Raku 正则表达式的 Unicode 字符类的广泛列表。因此在 Raku 中\d数字简写包括 Unicode 数字。您可以按照上面的方式枚举数字,或者使用字符类与连词组合将数字0..9子集/限制\d为 ASCII 数字,如下所示:<:ASCII>&&[<:ASCII> && \d]

~$ raku -pe ' s:g/ \< ( [ [<:ASCII> && \d] | <:Lu> | _ ]+ ) \> /\$$0/;'  file 

上面<:Lu>是“Letters-uppercase”的 Unicode 字符类。如果需要,<:ASCII>可以使用相同的技巧来子集为“ASCII 字母大写”(或更简单地,重新排列上面的方括号以重新组合)。

https://docs.raku.org/language/regexes#Unicode_properties
https://www.unicode.org/terminology/digits.html
https://docs.raku.org/language/regexes#Conjunction:_&&
https://docs.raku.org/language/regexes
https://raku.org

答案4

使用gawk

$ awk '{print gensub(/<([[:alnum:]_]+)>/, "$\\1", "g")}' file
# Or

$ awk '{print gensub(/<(\w+)>/, "$\\1", "g")}' file
This is a line with $VARIABLE1@$VARIABLE2.
This is a line with $VARIABLE3.
This is a line with $VARIABLE_UNKNOWN.
This is another line contains a<b.

在 gensub() 函数中,可以使用括号 as 来记忆子模式,captured group并在稍后使用backreferenceas引用它\n

来自GNU awk手册:

gensub()提供了一个附加功能,该功能不可用子()或者gsub():能够在替换文本中指定正则表达式的组件。这是通过在正则表达式中使用括号来标记组件然后指定来完成的'\N'在替换文本中,其中是 1 到 9 之间的数字。

相关内容