bash $ {VAR // tìm kiếm / thay thế} và hành vi regex kỳ lạ


8

Tôi đang cố gắng thực hiện một số tìm kiếm và thay thế trên một biến bằng cách sử dụng mở rộng tham số $ {VAR // search / thay thế}. Tôi có một PS1 khá dài và xấu, tôi muốn tìm ra kích thước sau khi mở rộng. Để làm như vậy tôi phải loại bỏ một loạt các chuỗi thoát tôi nhét vào đó. Tuy nhiên, khi cố gắng loại bỏ tất cả các chuỗi ANR CSI SGR, tôi đã gặp phải một vấn đề với cú pháp của mình.

Cho PS1 của tôi là:

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$

(vâng, tôi biết là bị bệnh ...)

Tôi đang cố gắng làm:

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

Tuy nhiên, những điều này dường như là tham lam ở điểm [0-9](gần như [0-9]được đối xử như một .thay thế):

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

Nếu tôi loại bỏ *và thay đổi [0-9]thành [0-9][0-9](vì nó mang tính minh họa hơn), tôi sẽ tiến gần hơn đến kết quả mong đợi:

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

Tại sao *(không hoặc nhiều hơn) làm những điều điên rồ? Am i thiếu cái gì ở đây? Nếu tôi vượt qua regex tương tự thông qua sed tôi sẽ nhận được kết quả như mong đợi:

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

3
Nó không phải là regex, nó chỉ là mô hình khớp tương tự như một tập tin toàn cầu. extglobkhông ảnh hưởng đến hành vi khớp mẫu.
jordanm

Bum, đó sẽ là lý do - tôi có linh cảm có thể là trường hợp: / Tôi đã cố gắng tìm hiểu rõ hơn về cơ chế khớp, nhưng không thành công lắm. đứng đầu để đọc về extglob (có vẻ như là một công việc cho sed!)
Drav Sloan

1
*([0-9])là tương đương với việc [0-9]*sử dụng extglob.
jordanm

1
Nếu bạn có câu trả lời đúng, bạn có thể chấp nhận trả lời câu hỏi của mình. Tôi rất vui vì đã cung cấp một số hướng dẫn.
jordanm

2
@DravSloan - nhắc nhở này là bệnh! 8-)
slm

Câu trả lời:


6

Âm thanh với tôi bạn muốn loại bỏ những thứ giữa \[\]:

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

Tuy nhiên, bashsự thay thế không hiệu quả đến mức bạn có thể nên bắn tốt hơn perlhoặc sedở đây, hoặc thực hiện nó trong một vòng lặp như:

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

(đó là cú pháp POSIX sh tiêu chuẩn ở trên, BTW).

Và nếu bạn muốn lời nhắc mở rộng từ đó:

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

4
Ngày của tôi đã hoàn tất, một loạt các biểu tượng của ma thuật cao tuổi lớn hơn từ High Priest of Command Line, Stephane. Tôi thề với một nửa số bài đăng của bạn, đôi mắt của tôi được đặt ở tốc độ truyền sai và tôi nhận được một màn hình lộn xộn :) Và vâng, mục đích cuối cùng là loại bỏ tất cả các chuỗi thoát: nó không tấn công tôi để loại bỏ giữa []. cảm ơn!
Drav Sloan

5

Sau một số hướng dẫn từ jordanm (và đọc phần "Kết hợp mẫu" của trang bash man), hóa ra các mẫu này được sử dụng bởi mở rộng tham số không phải là biểu thức chính quy. Tuy nhiên, đối với trường hợp cụ thể của tôi, nếu shopt extglobcó, tôi có thể làm:

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

nơi *([0-9])giống như [0-9]*trong regex.

Có vẻ như extglob cung cấp một số cơ chế tương tự như regex với (từ trang bash man):

          ?(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
Vâng, extglobthực hiện một tập hợp con của các khối lượng kshmở rộng. ksh93thực sự có một toán tử printf để chuyển đổi giữa các mẫu và (AT & T) REs ( printf '%P\n' '\\\[[0-9]*\\\]'cho *\\\[*([0-9])\\\]*)
Stéphane Chazelas

Hmm, có vẻ như * [0-9] hoạt động trong các truy vấn regex khác (không có dấu ngoặc tròn).
macieksk

0

Pure Bash đầy đủ các chuỗi ANSI được hỗ trợ

# 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\{|\}~]/}"
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.