Làm thế nào để thay thế một chuỗi con từ một biến?


7

Tôi đang cố gắng loại bỏ các ký tự từ một biến chuỗi. Nó hoạt động với tôi sednhư thế này:

MYVAR=--23ho02123ware38384you443d34o3434ingtod38384day-%§*#sfrf
echo ${MYVAR} | sed -e 's/[a-z][a-z0-9\-]*//g'

va tôi lây:

 --23%§*#

đó là những gì tôi đang tìm kiếm. Chuỗi phải bắt đầu bằng một chữ cái và chỉ chứa các chữ cái, chữ số và dấu gạch ngang (-). Có cách nào để đạt được điều này với bashchuỗi thay thế?

MYVAR=${MYVAR/[a-z][a-z0-9-]*/ }

Tôi đã thử một vài kết hợp, nhưng không có kết hợp nào hoạt động như tôi mong đợi.


thay thế chuỗi bash KHÔNG hỗ trợ regex! thay thế chuỗi bash đang thực hiện trên toàn cầu trong đó * bằng. * trong regex. kiểm tra en.wikipedia.org/wiki/Glob_(programming)
frams

Câu trả lời:


10

Bạn cần sử dụng các toán tử toàn cầu mở rộng ksh (một tập hợp con có sẵn bashcùng với shopt -s extglobzshvới set -o kshglob) để có được các biểu thức thông thường (mặc dù với một cú pháp khác: *(x)tương đương với x*ở đây):

shopt -s extglob # for bash
# set -o kshglob # for zsh
printf '%s\n' "${MYVAR//[[:alpha:]]*([[:alnum:]-])/}"

Hoặc với zsh extendedglobs trong đó tương đương với biểu thức chính quy *#:

set -o extendedglob
printf '%s\n' ${MYVAR//[[:alpha:]][[:alnum:]-]#}

Một vài lưu ý:

  • ${var/pattern/replacement}chỉ thay thế sự xuất hiện đầu tiên. Sử dụng ${var//pattern/replacement}để thay thế mỗi lần xuất hiện (như với gcờ trong sed's slệnh).
  • bạn đã thay thế một nhân vật không gian. Sử dụng ${var//pattern/}(hoặc ${var//pattern}) để thay thế bằng chuỗi trống.
  • Bạn không muốn sử dụng echođể xuất các chuỗi tùy ý
  • Ngoại trừ zsh, mở rộng biến trong bối cảnh danh sách phải được trích dẫn
  • hành vi sẽ khác so với sedcách tiếp cận của bạn khi biến chứa các ký tự dòng mới.
  • [a-z]trận ký tự (đối chiếu các yếu tố trong một số công cụ) bao gồm giữa az, danh sách trong đó thay đổi theo địa phương, hệ thống và các công cụ (ví dụ [a-z]với bash-4.3trong một en_GB.UTF-8miền địa phương vào một trận đấu hệ thống GNU A, X, é, , nhưng không phải Z). Điều đó thường bao gồm 26 chữ cái viết thường của bảng chữ cái tiếng Anh nhưng không nhất thiết phải như vậy. [[:alpha:]]bao gồm các ký tự (hoặc các yếu tố đối chiếu) được coi là bảng chữ cái (bất kể trường hợp nào) trong ngôn ngữ của bạn. Nếu bạn chỉ muốn khớp 26 chữ cái tiếng Anh, hãy sử dụng [abcdefghijklmnopqrstuvwxyz]hoặc sửa ngôn ngữ thành C( LC_ALL=C) và chỉ sử dụng [a-z]hoặc [[:lower:]]cho các chữ cái tiếng Anh viết thường hoặc [a-zA-Z]/[[:alpha:]] cho bất kỳ chữ cái tiếng Anh.
  • [a-z0-9\-]trong sedkhông khớp với ký tự dấu gạch chéo ngược, sử dụng [a-z0-9-]thay thế ( -phải là đầu tiên hoặc cuối cùng được thực hiện theo nghĩa đen).

cũng có thể thêm //tương đương với gcờ trái ngược với /OP được sử dụng và không gian cuối cùng trong nỗ lực của OP sẽ thay thế mẫu phù hợp với không gian
Sundeep

1
Cảm ơn rất nhiều Stéphane Chazelas, nó hoạt động như một bùa mê, ngay cả khi không có các nhà khai thác toàn cầu mở rộng ksh shopt -s extglob. Tốt nhất
dings

ĐÚNG: extglob shopt đã được kích hoạt trên máy của tôi, vì vậy tôi thực sự cần nó! Cảm ơn một lần nữa
dings

giải thích tốt đẹp! Tôi thấy nhân vật không gian trong sự thay thế của tôi, mà tôi đã sửa. Tôi đang sử dụng ngôn ngữ en_US.UTF-8 trên hệ thống, nhưng xuất de_DE.UTF-8 khi chạy tập lệnh để có thể chuyển đổi các chữ cái châu Âu thành các ký tự ASCII, vì en_US.UTF-8 không chuyển đổi chúng chính xác. Các ký tự dòng mới không phải là vấn đề, vì chuỗi này là thông tin đăng nhập của người dùng được nhập trong dấu nhắc bash. Đây là một phần của tập lệnh khổng lồ tôi đã viết để tạo tài khoản LDAP ở hai máy chủ khác nhau và tôi đang cố gắng buộc tập lệnh chỉ chấp nhận đăng nhập định dạng hợp lệ. Cảm ơn rât nhiều.
dings

1
@Seepeep, điểm tốt. Bây giờ tôi đã kết hợp những ghi chú đó và một vài điều nữa.
Stéphane Chazelas
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.