bash $ {VAR // search / replace} dan perilaku regex aneh


8

Saya mencoba melakukan pencarian dan mengganti variabel menggunakan ekspansi parameter $ {VAR // search / replace}. Saya memiliki PS1 yang cukup panjang dan jahat, bahwa saya ingin menghitung ukuran setelah ekspansi. Untuk melakukannya saya harus menghapus banyak urutan pelarian yang saya masukkan ke dalamnya. Namun ketika mencoba untuk menghapus semua urutan SGR ANSI CSI saya telah menemukan masalah dengan sintaksis saya.

Diberikan PS1 saya dari:

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$

(Ya itu sakit aku tahu ...)

Saya coba lakukan:

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

Namun ini tampaknya serakah pada titik [0-9](hampir seperti [0-9]diperlakukan sebagai .gantinya):

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

Jika saya menghapus *, dan mengubah [0-9]ke [0-9][0-9](karena itu lebih ilustratif) saya semakin mendekati hasil yang diharapkan:

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

Mengapa *(nol atau lebih) melakukan hal-hal gila? apakah saya melewatkan sesuatu di sini? Jika saya melewati regex yang sama melalui sed saya mendapatkan hasil yang diharapkan:

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

3
Ini bukan regex, itu hanya pencocokan pola yang mirip dengan file glob. extglobtidak mempengaruhi perilaku pencocokan pola.
jordanm

Bum, itu sebabnya - saya punya firasat itu mungkin terjadi: / Saya mencoba mencari klarifikasi mekanisme pencocokan, tanpa banyak keberhasilan. pergi membaca tentang extglob (sepertinya pekerjaan untuk sed!)
Drav Sloan

1
*([0-9])adalah setara [0-9]*dengan menggunakan extglob.
jordanm

1
Jika Anda mendapatkan jawaban yang benar, Anda dapat menjawab pertanyaan Anda sendiri. Saya senang telah memberikan beberapa petunjuk.
jordanm

2
@ DravSloan - prompt ini sakit! 8-)
slm

Jawaban:


6

Bagi saya, Anda ingin menghapus hal-hal antara \[dan \]:

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

Namun, bashpenggantian sangat tidak efisien sehingga Anda mungkin akan lebih baik menembak perlatau di sedsini, atau melakukannya dalam satu lingkaran seperti:

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

(itulah sintaks POSIX sh standar di atas, BTW).

Dan jika Anda ingin prompt yang diperluas dari itu:

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

4
Ah hari saya selesai, sekelompok simbol sihir tua yang lebih besar dari High Priest of Command Line, Stephane. Saya bersumpah untuk setengah dari posting Anda, mata saya diatur ke baud rate yang salah, dan saya mendapatkan layar berantakan :) Dan ya, tujuan akhirnya adalah untuk menghapus semua urutan melarikan diri: itu tidak mengejutkan saya untuk hanya menghapus antara [dan ]. Terima kasih!
Drav Sloan

5

Setelah beberapa panduan dari jordanm (dan membaca bagian "Pencocokan Pola" pada halaman bash man), ternyata pola-pola ini digunakan oleh ekspansi parameter bukan regex. Namun untuk kasus khusus saya, jika shopt extglobaktif, saya dapat melakukan:

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

di mana *([0-9])sama dengan [0-9]*di regex.

Tampaknya extglob menyediakan beberapa mekanisme yang mirip dengan regex dengan (dari halaman 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
Ya, extglobmengimplementasikan subset kshgumpalan diperpanjang. ksh93sebenarnya memiliki operator printf untuk mengkonversi antara pola dan (AT&T) RE ( printf '%P\n' '\\\[[0-9]*\\\]'memberi *\\\[*([0-9])\\\]*)
Stéphane Chazelas

Hmm, tampaknya * [0-9] berfungsi di kueri regex lain (tanpa kurung bundar).
macieksk

0

Pure Bash, rangkaian lengkap rangkaian ANSI yang didukung

# 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\{|\}~]/}"
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.