awk ou sed en minuscules / majuscules un seul caractère dans la chaîne?

13

Existe-t-il un moyen de mettre en majuscule / minuscule un seul caractère dans une chaîne?

Exemple d'entrée:

syslog_apr_24_30
syslog_mar_01_17

Sortie désirée:

syslog_Apr_24_30
syslog_Mar_01_17

Veuillez noter le début du mois en majuscules.

J'ai essayé awkmais je ne suis pas assez bon pour le faire fonctionner.

molni
la source

Réponses:

18

Vous pouvez utiliser \udans GNU sed pour mettre une lettre en majuscule:

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

Perl fait de même:

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

\l fait le contraire.

choroba
la source
8
Une touche plus simple: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
la source
3

Awk version avec sous-chaînes et toupper

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

Exemple d'exécution:

$ 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
la source
3

En utilisant awk:

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

ou

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

Exemple

% 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
UN B
la source
3

Voici une approche Perl:

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

Le -pfait imprimer chaque ligne après avoir appliqué le script donné par -e. La substitution remplace la première instance de _et le caractère qui la suit par eux-mêmes ( $&est tout ce qui a été apparié) en haut de casse ( uc()), eà la fin de l'opérateur de substitution ( s///e) est nécessaire afin d'évaluer les expressions.

terdon
la source
2

Un autre perl:

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

Pure Bash 4.x, en utilisant une expression régulière pour sélectionner la partie que vous souhaitez upcase, et l' ^^opérateur upcase sur cette partie. Agrafage à l'avant et à l'arrière (assorti par. *) Pour recréer la chaîne entière:

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

Si vous ne vous souvenez pas de toutes les règles de citation, il est sûr de tout citer sauf l'expression régulière (qui ferait =~une correspondance de chaîne littérale).

L' ^opérateur upcase-first ne fonctionne qu'au début d'une variable (ou d'un élément de tableau). Et il ne semble pas y avoir d'expansion de sous-chaîne qui vous donne ce que perl appellerait une valeur l (que vous pouvez attribuer à / modifier). Les opérateurs up / downcase-first peuvent prendre un modèle qui est apparié sur une base par caractère, mais cela n'aide pas à sauter syslog_, car il y a des noms de mois qui commencent par des caractères dans "syslog".

Quoi qu'il en soit, cela pourrait être plus rapide que foo="$(echo "$foo" | sed 's/_./\U&/')"(publié en tant que commentaire de la réponse acceptée, par Glenn Jackman).

Bash, sed ou awk sera BEAUCOUP plus rapide que perl. Si vous commencez à trouver plusieurs lignes simples perl utiles dans un script shell, vous devez simplement écrire le tout en perl.

Peter Cordes
la source
0

Si le mois suit toujours le premier "_" (trait de soulignement), utilisez-le (comme indiqué dans les autres réponses):

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

S'il peut y avoir d'autres soulignements avant celui qui précède le mois, alors ce qui précède ne fonctionnera pas.

Si le mois commence toujours par le 8ème caractère, alors utilisez ceci:

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