bash $ {VAR // search / replace}和奇怪的正则表达式行为


8

我正在尝试使用$ {VAR // search / replace}参数扩展对变量进行搜索和替换。我有一个相当漫长而邪恶的PS1,我想算出扩展后的大小。为此,我必须删除一堆我塞进其中的转义序列。但是,在尝试删除所有ANSI CSI SGR序列时,我遇到了语法问题。

鉴于我的PS1:

PS1=\[\033]0;[\h] \w\007\]\[\033[1m\]\[\033[37m\](\[\033[m\]\[\033[35m\]\u@\[\033[m
\]\[\033[32m\]\h\[\033[1m\]\[\033[37m\]\[\033[1m\])\[\033[m\]-\[\033[1m\](\[\033[m
\]\t\[\033[37m\]\[\033[1m\])\[\033[m\]-\[\033[1m\](\[\033[m\]\[\033[36m\]\w\[\033[1m
\]\[\033[37m\])\[\033[35m\]${git_branch}\[\033[m\]\n$

(是的,我知道病了...)

我正在尝试做:

# readability
search='\\\[\\033\[[0-9]*m\\\]'
# do the magic
sane="${PS1//$search/}"

但是这些似乎有点贪婪[0-9](几乎就像[0-9]被当作​​一个.替代):

echo "${PS1//$search/}"
\[\033]0;[\h] \w\007\]\n$ 

如果我删除*,然后更改[0-9][0-9][0-9](这是更说明性的),那么我将接近预期的结果:

$ search='\\\[\\033\[[0-9][0-9]m\\\]'
$ echo "${PS1//$search/}"
\[\033]0;[\h] \w\007\]\[\033[1m\](\[\033[m\]\u@\[\033[m\]\h\[\033[1m
\]\[\033[1m\])\[\033[m\]-\[\033[1m\](\[\033[m\]\t\[\033[1m\])\[\033[m\]-\[\033[1m
\](\[\033[m\]\w\[\033[1m\])$(git_branch)\[\033[m\]\n$ 

为什么*(零个或多个)做疯狂的事情?我在这里想念什么吗?如果我通过sed传递相同的正则表达式,则会得到预期的结果:

echo $PS1 | sed "s/$search//g"
\[\033]0;[\h] \w\007\](\u@\h)-(\t)-(\w)$(git_branch)\n$

3
它不是正则表达式,只是与文件glob类似的模式匹配。extglob确实会影响模式匹配行为。
jordanm

混蛋,这就是为什么-我直觉可能是这样:/我试图找到匹配机制的说明,但没有成功。前往阅读有关extglob的信息(看起来像sed的工作!)
Drav Sloan

1
*([0-9])等于[0-9]*使用extglob
jordanm

1
如果您得到正确的答案,可以回答您自己的问题。我很高兴提供一些指导。
jordanm

2
@DravSloan-此提示令人不适!8
slm

Answers:


6

在我看来,您想删除\[和之间的内容\]

$ shopt -s extglob
$ printf '%s\n' "${PS1//\\\[*(\\[^]]|[^\\])\\\]/}"
(\u@\h)-(\t)-(\w)${git_branch}\n$

但是,bash替换的效率很低,以至于您可能不希望在此处perlsed此处触发,也可以像这样循环执行:

p=$PS1 np=
while :; do
  case $p in
    (*\\\[*\\\]*) np=$np${p%%\\\[*};p=${p#*\\\]};;
    (*) break;;
  esac
done
np=$np$p
printf '%s\n' "$np"

(BTW是上面的标准POSIX sh语法)。

如果您想从中得到扩展提示:

ep=$(PS4=$np;exec 2>&1;set -x;:); ep=${ep%:}

4
我的一天结束了,来自命令行大祭司史蒂芬(Stephane)的另一束更高阶的魔法符号。我发誓占一半的职位,但我的视线被设置为错误的波特率,并且屏幕一片混乱:)是的,最终目的是删除所有转义序列:删除之间[和之间并不会打动我]。谢谢!
Drav Sloan

5

经过jordanm的一些指导(并阅读了bash手册页的“模式匹配”部分),事实证明参数扩展使用的这些模式不是regex。但是,对于我的特定情况,如果shopt extglob打开,则可以执行以下操作:

search='\\\[\\033\[*([0-9])m\\\]'

其中*([0-9])相同[0-9]*的正则表达式。

似乎extglob提供了一些与regex类似的机制(来自bash手册页):

          ?(pattern-list)
                 Matches zero or one occurrence of the given patterns
          *(pattern-list)
                 Matches zero or more occurrences of the given patterns
          +(pattern-list)
                 Matches one or more occurrences of the given patterns
          @(pattern-list)
                 Matches one of the given patterns
          !(pattern-list)
                 Matches anything except one of the given patterns

2
是的,extglob实现ksh扩展glob 的子集。ksh93实际上有一个printf运营商模式和(AT&T)的RE之间的转换(printf '%P\n' '\\\[[0-9]*\\\]'给人*\\\[*([0-9])\\\]*
斯特凡Chazelas

嗯,* [0-9]似乎可以在其他正则表达式查询中使用(没有圆括号)。
macieksk

0

支持纯Bash全系列ANSI序列

# Strips ANSI CSI (ECMA-48, ISO 6429) codes from text
# Param:
# 1: The text
# Return:
# &1: The ANSI stripped text
strip_ansi() {
  echo -n "${1//$'\e'[@A-Z\[\\\]\^_]*([0-9:;<=>?])*([ \!\"#$%&\'()\^*+,\-.\/])[@A-Z\[\\\]\^_\`a-z\{|\}~]/}"
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.