web-dev-qa-db-ja.com

awkまたはsedで小文字/大文字に文字列内の1文字のみ?

いくつかの文字列で1文字だけを大文字/小文字にする方法はありますか?

入力例:

syslog_apr_24_30
syslog_mar_01_17

望ましい出力:

syslog_Apr_24_30
syslog_Mar_01_17

月の初めは大文字にしてください。

私はawkを試しましたが、動作させるには十分ではありません。

13
molni

GNUで\uを使用すると、大文字にセッドされます:

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

Perlも同じことをします:

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

\lはその逆です。

18
choroba

awk:

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

Awkバージョンとサブストリングおよびトッパー

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
A.B.

これがPerlのアプローチです:

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

_-p_は、_-e_で指定されたスクリプトを適用した後に各行を印刷します。置換は、___の最初のインスタンスとそれに続く文字をそれ自体で置き換えます(_$&_は一致したものです)大文字(uc())、The e at式を評価するには、置換演算子の最後(_s///e_)が必要です。

3
terdon

別のPerl

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

正規表現を使用して大文字に変換する部分を選択するPure Bash 4.xと、その部分の_^^_大文字演算子。文字列全体を再作成するために、前後にタック(。*で一致)します。

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

すべての引用ルールを覚えていない場合は、正規表現(_=~_に文字列の一致を行わせる)以外のすべてを引用しても安全です。

_^_ upcase-first演算子は、変数(または配列要素)の先頭でのみ機能します。そして、Perlがlvalueと呼ぶもの(ユーザーが割り当て/変更できる)を提供する部分文字列展開はないようです。 up/downcase-first演算子は、文字ごとに一致するパターンを取ることができますが、「syslog」に文字で始まる月の名前があるため、_syslog__をスキップするのには役立ちません。

とにかく、これはfoo="$(echo "$foo" | sed 's/_./\U&/')"(Glenn Jackmanによる、承認された回答へのコメントとして投稿)よりも高速かもしれません。

Bash、sed、またはawkは、Perlよりも何倍も速くなります。シェルスクリプトで便利な複数のPerlワンライナーを見つけ始めたら、すべてをPerlで書くだけです。

1
Peter Cordes

月が常に最初の "_"(アンダースコア)の後に続く場合は、これを使用します(他の回答に示されています)。

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

その月の前のアンダースコアが他にある場合、上記は機能しません。

月が常に8番目の文字で始まる場合は、次のようにします。

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