使用 sed 如何在一行上替换更大模式中的两个模式?
给定一行文本,我想找到一个模式(我们称之为外部模式),然后在该外部模式内替换两个内部模式。
以下是输入文本的一行示例:
Z:\source\private\main\developer\foo\setenv.sh(25): export 'FONTCONFIG_PATH'="$WINE_SHARED_SUPPORT/X11/etc/fonts"
在上面的例子中,外部模式/^.*\([[:digit:]]+\):/
应该相等,Z:\source\private\main\developer\foo\setenv.sh(25):
而两个内部模式是/^[A-Za-z]:/
和/\\/
。
提出我的问题的另一种方式是:
使用 sed 我知道如何使用命令执行模式替换s
,但如何限制命令的范围s
以使其仅对输入字符串的部分起作用(25):
?
我试图获得的最终结果是将文本行转换为如下形式:
/enlistments/source/private/main/developer/foo/setenv.sh(25): export 'FONTCONFIG_PATH'="$WINE_SHARED_SUPPORT/X11/etc/fonts"
答案1
此命令将您的输入示例转换为输出示例:
sed 's|\\|/|g;s|^[^/]*|/enlistments|'
如果您的某些输入在部分之后的部分包含反斜杠/^.*([[:digit:]]+):/
,那么您将必须分而治之以防止后面的反斜杠被替换。
sed 'h;s/^.*([[:digit:]]\+)://;x;s/^\(.*([[:digit:]]\+):\).*/\1/;s|\\|/|g;s|^[^/]*|/enlistments|;G;s/\n//'
说明(标有星号的步骤([*]
)适用于两个命令):
h
- 复制该行以保留空间s/^.*([[:digit:]]\+)://
- 从模式空间中删除原始行的第一部分x
- 交换模式空间和保持空间s/^\(.*([[:digit:]]\+):\).*/\1/
- 保留副本中该行的第一部分(丢弃最后一部分)s|\\|/|g
-[*
]将所有反斜杠改为斜杠(在分治版本中,只有模式空间中的部分 - 即行的第一部分 - 受到影响)s|^[^/]*|/enlistments|
-[*
]将第一个斜线之前的内容更改为“/enlistments” - 如果需要,可以使其更具选择性G
- 将换行符和保留空间的内容附加到模式空间的末尾s/\n//
- 删除内部换行符
答案2
我认为有两个事实对你有用:
默认情况下,
sed
只会替换一行中第一次出现的字符串。因此,给定以下行:foo foo
该命令
sed s/foo/bar/
将导致:bar foo
您可以将 sed 命令限制为与特定模式匹配的行。如果您只想对包含字符串“xyz”的行执行上述替换,则可以使用如下命令:
sed '/xyz/ s/foo/bar/'
我认为这应该可以帮助你做你想做的事。
答案3
你可以尝试
sed -r 's/^[A-Z]:\\|\\/\//g' | sed 's/^/\/enlistments/'
现在,这当然要求 (25): 后面的部分没有反斜杠才能工作。但我怀疑,由于 unix 路径结构,这种情况永远不会发生。
答案4
这可能对你有用(GNU sed):
sed 's/([0-9]\+):/&\n/;h;s/\n.*//;y/\\/\//;s/[^/]*/\/enlistments/;G;s/\n.*\n//' file