awk atau sed untuk huruf kecil / besar hanya satu karakter dalam string?

13

Apakah ada cara bagaimana huruf besar / kecil hanya satu karakter dalam beberapa string?

Contoh Input:

syslog_apr_24_30
syslog_mar_01_17

Output yang diinginkan:

syslog_Apr_24_30
syslog_Mar_01_17

Harap dicatat huruf besar awal bulan.

Saya sudah mencoba awktetapi saya tidak cukup baik untuk membuatnya bekerja.

Molni
sumber

Jawaban:

18

Anda dapat menggunakan \used GNU untuk huruf besar:

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

Perl melakukan hal yang sama:

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

\l melakukan yang sebaliknya.

choroba
sumber
8
Sentuhan sederhana:sed 's/_./\U&/'
glenn jackman
4

awk:

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

Awk versi dengan substring dan toupper

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

Contoh dijalankan:

$ 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
Sergiy Kolodyazhnyy
sumber
3

Menggunakan awk:

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

atau

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

Contoh

% 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
AB
sumber
3

Inilah pendekatan Perl:

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

The -pmenyebabkan setiap baris untuk dicetak setelah menerapkan script yang diberikan oleh -e. Substitusi menggantikan instance pertama _dan karakter yang mengikutinya dengan diri mereka sendiri ( $&adalah apa pun yang cocok) huruf besar ( uc()), epada akhir operator substitusi ( s///e) diperlukan untuk mengevaluasi ekspresi.

terdon
sumber
2

Lainnya perl:

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

Pure Bash 4.x, menggunakan regex untuk memilih bagian yang ingin Anda kirimi huruf besar, dan ^^operator huruf besar pada bagian itu. Memaku di bagian depan dan belakang (dicocokkan dengan. *) Untuk membuat kembali seluruh string:

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

Jika Anda tidak mengingat semua aturan penawaran, aman untuk mengutip semuanya kecuali regex (yang akan membuat =~pencocokan string secara literal).

The ^Operator upcase-pertama hanya bekerja pada awal variabel (atau elemen array). Dan sepertinya tidak ada ekspansi substring yang memberi Anda apa perl akan memanggil nilai (yang dapat Anda tetapkan / modifikasi). Operator naik / turun pertama dapat mengambil pola yang cocok pada basis per karakter, tetapi itu tidak membantu melompati syslog_, karena ada nama bulan yang dimulai dengan karakter dalam "syslog".

Bagaimanapun, ini mungkin lebih cepat daripada foo="$(echo "$foo" | sed 's/_./\U&/')" (diposting sebagai komentar untuk jawaban yang diterima, oleh Glenn Jackman).

Bash, sed, atau awk akan BANYAK kali lebih cepat dari perl. Jika Anda mulai menemukan beberapa perl satu-liners yang berguna dalam skrip shell, Anda harus menulis semuanya dalam perl.

Peter Cordes
sumber
0

Jika bulan selalu mengikuti "_" pertama (garis bawah), maka gunakan ini (seperti yang ditunjukkan dalam jawaban lain):

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

Jika mungkin ada garis bawah lainnya sebelum yang sebelum bulan maka di atas tidak akan berfungsi.

Jika bulan selalu dimulai dengan karakter ke-8, gunakan ini:

sed -e 's/^\(.\{7\}\)\(.\)/\1\u\2/'
Kevin Fegan
sumber