awk hoặc sed để viết thường / viết hoa chỉ một ký tự trong chuỗi?


13

Có cách nào để viết hoa / viết thường chỉ một ký tự trong một chuỗi không?

Ví dụ đầu vào:

syslog_apr_24_30
syslog_mar_01_17

Sản phẩm chất lượng:

syslog_Apr_24_30
syslog_Mar_01_17

Lưu ý xin vui lòng viết hoa đầu tháng.

Tôi đã cố gắng awknhưng tôi không đủ tốt để làm cho nó hoạt động.

Câu trả lời:


18

Bạn có thể sử dụng \utrong GNU sed để viết hoa một chữ cái:

sed -e 's/_\(.\)/_\u\1/' input

Perl cũng làm như vậy:

perl -pe 's/_(.)/_\u$1/' input

\l làm ngược lại.


8
Một liên lạc đơn giản hơn:sed 's/_./\U&/'
glenn jackman

4

ôi

echo "syslog_apr_24_30" | 
  awk -F'_' '{print $1"_"toupper(substr($2,1,1)) substr($2,2)  "_"$3"_"$4}'

3

Awk phiên bản với chất nền và toupper

awk 'BEGIN{ FS=OFS="_"} {
        cap=toupper(substr($2,1,1));
        lower=substr($2,2,3);
        $2 = cap lower; print 
}' list.txt 

Chạy mẫu:

$ awk 'BEGIN{ FS=OFS="_"} { 
    cap=toupper(substr($2,1,1));
    lower=substr($2,2,3);$2 = cap lower; print 
}' list.txt               
syslog_Apr_24_30
syslog_Mar_01_17

3

Sử dụng awk:

awk -F_ '{
    printf "%s_%s_%s_%s",$1,toupper(substr($2,1,1))substr($2,2,2),$3,$4"\n"
}' foo

hoặc là

awk -F_ '{
    for(i=1;i<=NF;i++) {
        if(i==2){
            printf "%s",toupper(substr($i,1,1))substr($i,2,length($i)-1)
        } 
        else {printf "%s",$i} 
        if(i<NF) {printf "%s","_"}
    } printf "%s","\n"}' foo

Thí dụ

% cat foo
syslog_apr_24_30
syslog_mar_01_17

% awk -F_ '{for(i=1;i<=NF;i++) {if(i==2){printf "%s",toupper(substr($i,1,1))substr($i,2,length($i)-1)} else {printf "%s",$i} if(i<NF) {printf "%s","_"}} printf "%s","\n"}' foo
syslog_Apr_24_30
syslog_Mar_01_17

% awk -F_ '{printf "%s_%s_%s_%s",$1,toupper(substr($2,1,1))substr($2,2,2),$3,$4"\n"}' foo 
syslog_Apr_24_30
syslog_Mar_01_17

3

Đây là một cách tiếp cận Perl:

$ perl -pe 's/_./uc($&)/e' file
syslog_Apr_24_30
syslog_Mar_01_17

Các -pnguyên nhân mỗi dòng được in sau khi áp dụng tập lệnh được đưa ra bởi -e. Sự thay thế thay thế thể hiện đầu tiên _và ký tự theo sau nó với chính nó ( $&là bất cứ thứ gì được khớp) ở trên ( uc()), eở cuối toán tử thay thế ( s///e) là cần thiết để đánh giá các biểu thức.


2

Khác perl:

perl -F_ -anle '$F[1] = ucfirst $F[1];print join "_", @F'

1

Pure Bash 4.x, sử dụng regex để chọn ra phần bạn muốn incase và ^^toán tử upcase trên phần đó. Xử lý ở mặt trước và mặt sau (khớp với. *) Để tạo lại toàn bộ chuỗi:

foo=syslog_apr_24_30
if [[ $foo =~ (.*)(_[a-z])(.*) ]]; then
    foo=${BASH_REMATCH[1]}${BASH_REMATCH[2]^^}${BASH_REMATCH[3]}
fi

Nếu bạn không nhớ tất cả các quy tắc trích dẫn, sẽ an toàn khi trích dẫn mọi thứ trừ regex (điều này sẽ tạo ra =~một chuỗi khớp theo nghĩa đen).

Các ^nhà điều hành upcase đầu tiên chỉ hoạt động vào đầu của một biến (hoặc phần tử mảng). Và dường như không có bất kỳ sự mở rộng chuỗi con nào cung cấp cho bạn cái mà perl sẽ gọi là một giá trị (mà bạn có thể gán cho / sửa đổi). Các toán tử đầu tiên lên / xuống có thể lấy một mẫu phù hợp trên cơ sở mỗi ký tự, nhưng điều đó không giúp bỏ qua syslog_, bởi vì có những tên tháng bắt đầu bằng các ký tự trong "syslog".

Dù sao, điều này có thể nhanh hơn foo="$(echo "$foo" | sed 's/_./\U&/')"(được đăng dưới dạng bình luận cho câu trả lời được chấp nhận, bởi Glenn Jackman).

Bash, sed hoặc awk sẽ nhanh hơn NHIỀU lần so với perl. Nếu bạn bắt đầu tìm thấy nhiều perl một liners hữu ích trong tập lệnh shell, bạn chỉ nên viết toàn bộ trong perl.


0

Nếu tháng luôn theo sau "_" đầu tiên (gạch dưới), thì hãy sử dụng giá trị này (như thể hiện trong các câu trả lời khác):

sed -e 's/_\(.\)/_\u\1/'

Nếu có thể có dấu gạch dưới khác trước một tháng trước thì những điều trên sẽ không hoạt động.

Nếu tháng luôn bắt đầu bằng ký tự thứ 8, thì hãy sử dụng:

sed -e 's/^\(.\{7\}\)\(.\)/\1\u\2/'
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.