bash ${VAR//search/replace} 및 이상한 정규식 동작

bash ${VAR//search/replace} 및 이상한 정규식 동작

${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$ 

*(0개 이상) 미친 짓을 할까요? 여기서 뭔가 빠졌나요? sed를 통해 동일한 정규식을 전달하면 예상되는 결과를 얻습니다.

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

답변1

\[와 사이의 항목을 제거하려는 것 같습니다 \].

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

그러나 대체는 매우 비효율적이므로 bash여기에서 perlOR을 실행 sed하거나 다음과 같이 루프에서 수행하는 것이 더 나을 것입니다.

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

(그런데 이것은 위의 표준 POSIX sh 구문입니다.)

네가 원한다면확장하다힌트:

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

답변2

jordanm의 안내를 받은 후(그리고 bash 매뉴얼 페이지의 "패턴 일치" 섹션을 읽은 후) 매개변수 확장에 사용되는 이러한 패턴은 정규식이 아니라는 것이 밝혀졌습니다. 하지만 내 특별한 경우에 shopt extglob켜져 있으면 다음과 같이 할 수 있습니다.

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

*([0-9])여기서는 정규식과 동일 합니다 [0-9]*.

extglob은 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

답변3

Pure Bash 전체 범위의 ANSI 시퀀스 지원

# Strips ANSI CSI (ECMA-48, ISO 6429) codes from text
# Param:
# 1: The text
# Return:
# &1: The ANSI stripped text
strip_ansi() {
  shopt -s extglob
  printf %s "${1//$'\e'[@A-Z\[\\\]\^_]*([0-9:;<=>?])*([ \!\"#$%&\'()\^*+,\-.\/])[@A-Z\[\\\]\^_\`a-z\{|\}~]/}"
}

관련 정보