Regex 如何在线的匹配部分内执行sed变换

Regex 如何在线的匹配部分内执行sed变换,regex,bash,awk,replace,sed,Regex,Bash,Awk,Replace,Sed,在与特定模式匹配的直线内进行sed变换很容易,但如果我们只想变换直线的特定部分,该怎么办 简单例子 假设我们要使所有以#开头的行中的所有字符都大写。我们可以通过以下形式的命令来实现这一点 sed '/^#/ y/abcdef/ABCDEF/' 假设我们只想把这些行中的第一个单词变成大写。我们将如何使用sed翻译 更高级的应用程序 我想在git的输出的图形部分用反斜杠交换斜杠--无寻呼机日志--全部--图形--装饰--单线--颜色=始终| tac 以前 之后 请注意,提交消息中的任何斜杠都保持不

在与特定模式匹配的直线内进行sed变换很容易,但如果我们只想变换直线的特定部分,该怎么办

简单例子 假设我们要使所有以
#
开头的行中的所有字符都大写。我们可以通过以下形式的命令来实现这一点

sed '/^#/ y/abcdef/ABCDEF/'
假设我们只想把这些行中的第一个单词变成大写。我们将如何使用sed翻译

更高级的应用程序 我想在
git的输出的图形部分用反斜杠交换斜杠--无寻呼机日志--全部--图形--装饰--单线--颜色=始终| tac

以前

之后


请注意,提交消息中的任何斜杠都保持不变,但图形部分中的斜杠会被转换。

如果您的sed版本支持它,您可以使用
\U
将文本转换为大写:

sed -r 's/(^# *)([^ ]*)/\1\U\2/'
这将捕获以
#
开头的任何行的第一部分(包括可选空格),然后是直到下一个空格字符的任何内容。第二个捕获组被转换为大写

如果它不支持,则始终可以使用perl:

perl -pe 's/(^#\s*)([\S]*)/$1\U$2/'
我在这个版本中使用了
\s
\s
,它们分别相当于
[[:space:]
(空格字符)和
[^[:space:]
(非空格字符)。您可能希望使用稍微不同的模式,具体取决于您正在处理的文件的具体情况。

这可能适合您(GNU-sed):

或:


保持简单,只需使用awk。e、 g.第三个参数要匹配的GNU awk()

添加任何awk和注释,以防脚本的功能不明显:

$ cat tst.awk        
{
    match($0,/[| *\/\\]+/)              # find the segment of text you want
    tgt = substr($0,RSTART,RLENGTH)     # save that segment in a variable tgt
    gsub(/\//,RS,tgt)                   # change all /s to newlines in tgt
    gsub(/\\/,"/",tgt)                  # change all \s to /s in tgt
    gsub(RS,"\\",tgt)                   # change all newlines to \s in tgt
    print tgt substr($0,RSTART+RLENGTH) # print tgt plus rest of the line
}
我们在字符交换期间使用换行符作为tmp值,因为保证换行符中不会出现换行符

顺便说一句,要将以
#
开头的每行的第一个单词改为大写,可以是:

awk '/^#/{$1=toupper($1)}1' file
或:

根据您的输入数据、
单词的定义和空格要求

如果您想要匹配的文本可以包含控制字符,就像您的注释中所说的那样,那么只需在regexp中允许它,例如:

    match($0,/([[:space:][:cntrl:]|*\/\\]+)(.*)/,a)

这里有一个简单的sed解决方案,它应该是可移植的(即在GNU以外的sed变体中工作)。这将交换不跟随字母的斜杠(至少在示例数据中有效)

这方面的细分有点像这样:

  • s:\([^a-z]\)/:\1\\:g
    -用反斜杠替换正斜杠
  • t
    -如果我们只是做了一次替换,请跳到末尾(避免下一次替换)
  • s:\([^a-z]\)\:\1/:g
    -将反斜杠替换为正斜杠

将其拆分为两个
-e
表达式的原因是sed的一些变体要求分支名称位于脚本中的一行末尾。
-e
表达式的结尾被视为等同于行的结尾。

向我们展示一个输入和所需输出的示例会更有用。您介意解释后一个复杂表达式的作用吗?向我们展示该命令的输出示例,以及您希望将其转换为的内容。我不清楚它与您的原始需求有何关系。我注意到在您的示例中,
origin/DR-01
已更改为
origin\DR-01
——这是有意的吗?顺便说一句,我认为你应该摆脱你原来的例子,把重点放在与你的git输出相关的特定问题上,因为这会让你的问题更清楚。所以,给我们展示你想要的,否则有人会给你一个同样的答案!命令git--no-pager log--all--graph--decoration--oneline--color=always | tac | sed-e's:\([^a-z]\)/:\1\:g;t'-e's:\([^a-z]\)\:\1/:g'
似乎不起作用。斜杠没有被碰。@chieltenbrink-切换到
--color=never
,它就工作了。散落在不同颜色字符之间的ANSI/vt100/xterm代码妨碍了sed对该行的解释。要查看真正发生的情况,请尝试查看通过
cat-et
传输的
git
命令的转储。当颜色设置为
^[[33m
,sed看到的是
m
。如果您可以选择不使用颜色,我的答案中的sed脚本将起作用。如果没有,则需要更复杂的内容。添加这样的量词似乎有效:
git--no-pager log--all--graph--decoration--oneline--color=always | tac | sed-e's:\([^a-z]*\)/:\1\:g;t'-e's:\([^a-z]*\)\:\1/:g'
。如果允许在(背面)前“零个或多个非字母”斜杠,您允许将
origin/DR-01
转换为
origin\DR-01
。这不是解决办法。这似乎不适用于标记
--color=always
。我不知道这意味着什么,awk没有
--color=always
标记。如果您有一些上面不适用的输入集,请将您的问题编辑为显示该输入和预期输出。该脚本适用于发布的示例输入或任何以空格、/、\、|和/或*字符序列开头的其他字符。哦,我从另一个答案下的注释中看到,您正在运行一些命令,将控制字符注入文本中-只需将括号表达式中的``更改为includee控制字符(例如,
^[:打印:
)脚本会运行的。谢谢!记录在案,OP包括我正在尝试处理命令
git--no pager log--all--graph--decoration--oneline--color=always | tac
。是的,它会运行。但是对于那些没有
git
并且对它的输出一无所知的人,我们所要做的就是你输入的示例在你的问题中提供,我们倾向于忽略你所说的任何命令
sed '/^#/!b;s/\w\w*/&\n/;h;y/abcdef/ABCDEF/;G;s/\n.*\n//' file
$ cat tst.awk        
{
    match($0,/([| *\/\\]+)(.*)/,a)
    gsub(/\//,RS,a[1])
    gsub(/\\/,"/",a[1])
    gsub(RS,"\\",a[1])
    print a[1] a[2]
}

$ awk -f tst.awk file
| * | | 279e9ad (tag: v0.0.4.334, origin/DR) asdfasdf
| | |\ \
| |\| \ \
| | |\ \ \
| | |/ / /
| | * | |   1fc7ab7 (tag: v0.0.4.337) Merge branch 'DR' into NextMajor
| | | * | d24e21d (tag: v0.0.4.341, origin/DR-01) DR-010728 Updated unit tests
| | |/ /
| | * |   8c01099 (tag: v0.0.4.338, tag: 0.0.4_MILESTONE_RELEASE) Merge 
$ cat tst.awk        
{
    match($0,/[| *\/\\]+/)              # find the segment of text you want
    tgt = substr($0,RSTART,RLENGTH)     # save that segment in a variable tgt
    gsub(/\//,RS,tgt)                   # change all /s to newlines in tgt
    gsub(/\\/,"/",tgt)                  # change all \s to /s in tgt
    gsub(RS,"\\",tgt)                   # change all newlines to \s in tgt
    print tgt substr($0,RSTART+RLENGTH) # print tgt plus rest of the line
}
awk '/^#/{$1=toupper($1)}1' file
awk '/^#/{$2=toupper($2)}1' file
    match($0,/([[:space:][:cntrl:]|*\/\\]+)(.*)/,a)
sed -e 's:\([^a-z]\)/:\1\\:g;t' -e 's:\([^a-z]\)\\:\1/:g' file