awk o sed a minúsculas / mayúsculas solo un caracter en cadena?

13

¿Hay alguna forma de poner en mayúsculas / minúsculas solo un carácter en alguna cadena?

Ejemplo de entrada:

syslog_apr_24_30
syslog_mar_01_17

Salida deseada:

syslog_Apr_24_30
syslog_Mar_01_17

Tenga en cuenta por favor el principio mayúscula del mes.

Lo he intentado awkpero no soy lo suficientemente bueno para que funcione.

molni
fuente

Respuestas:

18

Puede usar \uen GNU sed para poner en mayúscula una letra:

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

Perl hace lo mismo:

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

\l hace lo contrario

choroba
fuente
8
Un toque más 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
fuente
3

Awk versión con subcadenas y toupper

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

Ejecución de muestra:

$ 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
fuente
3

Utilizando awk:

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

o

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

Ejemplo

% 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
fuente
3

Aquí hay un enfoque de Perl:

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

La -pcausa cada línea impresa después de aplicar a la secuencia de comandos dada por -e. La sustitución reemplaza la primera instancia de _y el carácter que la sigue con ellos mismos ( $&es lo que fue emparejado) mayúscula ( uc()), se necesita eal final del operador de sustitución ( s///e) para evaluar las expresiones.

terdon
fuente
2

Otro perl:

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

Pure Bash 4.x, utilizando una expresión regular para seleccionar la parte que desea aumentar y el ^^operador de mayúsculas en esa parte. Tachado en la parte delantera y trasera (emparejado por. *) Para volver a crear la cadena completa:

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

Si no recuerda todas las reglas de comillas, es seguro citar todo excepto la expresión regular (que haría =~una coincidencia de cadena literal).

El ^operador upcase-first solo funciona al comienzo de una variable (o elemento de matriz). Y no parece haber ninguna expansión de subcadena que le proporcione lo que Perl llamaría un valor (que puede asignar / modificar). Los operadores de mayúsculas / minúsculas pueden tomar un patrón que coincida por carácter, pero eso no ayuda a saltar syslog_, ya que hay nombres de meses que comienzan con caracteres en "syslog".

De todos modos, esto podría ser más rápido que foo="$(echo "$foo" | sed 's/_./\U&/')"(publicado como un comentario a la respuesta aceptada, por Glenn Jackman).

Bash, sed o awk serán MUCHAS veces más rápido que perl. Si comienza a encontrar varias líneas de unl perl útiles en un script de shell, simplemente debe escribir todo en perl.

Peter Cordes
fuente
0

Si el mes siempre sigue al primer "_" (guión bajo), entonces use esto (como se muestra en otras respuestas):

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

Si puede haber otros guiones bajos antes del anterior al mes, entonces lo anterior no funcionará.

Si el mes siempre comienza con el octavo carácter, use esto:

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