awk หรือ sed เพื่อพิมพ์เล็ก / พิมพ์ใหญ่อักขระเดียวในสตริง?


13

มีวิธีการตัวพิมพ์ใหญ่ / ตัวพิมพ์เล็กเพียงตัวเดียวในบางสาย?

ตัวอย่างอินพุต:

syslog_apr_24_30
syslog_mar_01_17

ผลลัพธ์ที่ต้องการ:

syslog_Apr_24_30
syslog_Mar_01_17

หมายเหตุโปรดเริ่มต้นตัวพิมพ์ใหญ่ของเดือน

ฉันลองแล้วawkแต่ยังไม่ดีพอที่จะทำให้มันทำงานได้

คำตอบ:


18

คุณสามารถใช้\uใน GNU เพื่อพิมพ์อักษร:

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

Perl ทำเช่นเดียวกัน:

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

\l ไม่ตรงข้าม


8
สัมผัสที่ง่ายกว่า:sed 's/_./\U&/'
เกล็นแจ็คแมน


3

Awk เวอร์ชันที่มีสตริงย่อยและ toupper

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

วิ่งตัวอย่าง:

$ 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

การใช้awk:

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

หรือ

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

ตัวอย่าง

% 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

นี่เป็นวิธี Perl:

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

ทำให้เกิดแต่ละบรรทัดในการพิมพ์หลังจากการใช้สคริปต์ที่กำหนดโดย-p -eการแทนที่จะแทนที่อินสแตนซ์แรกของ_และอักขระที่ตามมาด้วยตัวเอง ( $&คืออะไรก็ตามที่ตรงกัน) ตัวพิมพ์ใหญ่บน ( uc()), eตอนท้ายของตัวดำเนินการแทน ( s///e) จำเป็นต้องมีเพื่อประเมินนิพจน์



1

Pure Bash 4.x ใช้ regex เพื่อเลือกชิ้นส่วนที่คุณต้องการ upcase และตัว^^ดำเนินการ upcase ในส่วนนั้น การตรึงที่ด้านหน้าและด้านหลัง (จับคู่ด้วย. *) เพื่อสร้างสตริงใหม่ทั้งหมด:

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

หากคุณไม่จำกฎการอ้างอิงทั้งหมดมันปลอดภัยที่จะพูดทุกอย่างยกเว้น regex (ซึ่งจะทำให้=~การจับคู่สตริงตามตัวอักษร)

ตัวดำเนินการ^upcase-first จะทำงานที่จุดเริ่มต้นของตัวแปร (หรือองค์ประกอบอาร์เรย์) เท่านั้น และดูเหมือนจะไม่มีการขยาย substring ใด ๆ ที่ให้สิ่งที่ Perl จะเรียก lvalue (ที่คุณสามารถกำหนดให้ / แก้ไข) ตัวดำเนินการ up / downcase-first สามารถใช้รูปแบบที่จับคู่ตามตัวอักษร แต่นั่นไม่ได้ช่วยข้ามsyslog_เพราะมีชื่อเดือนที่ขึ้นต้นด้วยตัวอักษรใน "syslog"

อย่างไรก็ตามนี่อาจเร็วกว่าfoo="$(echo "$foo" | sed 's/_./\U&/')"(โพสต์เป็นความคิดเห็นต่อคำตอบที่ยอมรับโดย Glenn Jackman)

Bash, sed หรือ awk จะเร็วกว่า Perl หลายเท่า หากคุณเริ่มหา Perl หนึ่ง liners หลายประโยชน์ในเชลล์สคริปต์คุณควรเขียนทุกสิ่งใน Perl


0

หากเดือนนั้นตามหลังเครื่องหมาย "_" ครั้งแรก (ขีดล่าง) ให้ใช้คำนี้ (ดังที่แสดงในคำตอบอื่น ๆ ):

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

หากอาจมีขีดล่างอื่น ๆ ก่อนหนึ่งเดือนก่อนหน้านี้ข้างต้นจะไม่ทำงาน

หากเดือนขึ้นต้นด้วยตัวอักษรที่ 8 ให้ใช้คำนี้:

sed -e 's/^\(.\{7\}\)\(.\)/\1\u\2/'
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.