Você pode usar \u
no GNU sed para uma letra maiúscula:
sed -e 's/_\(.\)/_\u/' input
Perl faz o mesmo:
perl -pe 's/_(.)/_\u$1/' input
\l
faz o oposto.
Existe uma maneira de maiúsculas / minúsculas apenas um caractere em alguma string?
Exemplo de entrada:
syslog_apr_24_30
syslog_mar_01_17
Saída desejada:
syslog_Apr_24_30
syslog_Mar_01_17
Note por favor o início maiúsculo do mês.
Eu tentei awk
, mas não sou bom o suficiente para funcionar.
echo "syslog_apr_24_30" |
awk -F'_' '{print $1"_"toupper(substr($2,1,1)) substr($2,2) "_"$3"_"$4}'
Awk
version com substrings e toupper
awk 'BEGIN{ FS=OFS="_"} {
cap=toupper(substr($2,1,1));
lower=substr($2,2,3);
$2 = cap lower; print
}' list.txt
Execução da amostra:
$ 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
Usando 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
Exemplo
% 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
Aqui está uma abordagem de Perl:
$ perl -pe 's/_./uc($&)/e' file
syslog_Apr_24_30
syslog_Mar_01_17
O -p
faz com que cada linha seja impressa depois de aplicar o script fornecido por -e
. A substituição substitui a primeira instância de _
eo caractere seguinte por ela ( $&
é o que foi correspondido) maiúscula ( uc()
), O e
no final do operador de substituição ( s///e
) é necessário para avaliar expressões.
Outro perl
:
perl -F_ -anle '$F[1] = ucfirst $F[1];print join "_", @F'
Pure Bash 4.x, usando um regex para escolher a parte que você deseja atualizar, e o operador ^^
upcase nessa parte. Tacking na frente e nas costas (correspondido por. *) Para recriar toda a string:
foo=syslog_apr_24_30
if [[ $foo =~ (.*)(_[a-z])(.*) ]]; then
foo=${BASH_REMATCH[1]}${BASH_REMATCH[2]^^}${BASH_REMATCH[3]}
fi
Se você não se lembra de todas as regras de cotação, é seguro citar tudo, exceto o regex (o que tornaria =~
uma correspondência literal de string).
O operador ^
upcase-first só funciona no início de uma variável (ou elemento de matriz). E não parece haver nenhuma expansão de substring que forneça o que o perl chamaria de lvalue (que você pode atribuir a / modify). Os operadores up / downcase-first podem obter um padrão que seja correspondido por caractere, mas isso não ajuda a ignorar syslog_
, porque existem nomes de mês que começam com caracteres em "syslog".
De qualquer forma, isso pode ser mais rápido que foo="$(echo "$foo" | sed 's/_./\U&/')"
(postado como um comentário para a resposta aceita, por Glenn Jackman).
Bash, sed ou awk serão MUITO vezes mais rápidos que o perl. Se você começar a encontrar múltiplos one-liners perl úteis em um shell script, você deve simplesmente escrever tudo em perl.
Se o mês sempre segue o primeiro "_" (sublinhado), então use isto (como mostrado em outras respostas):
sed -e 's/_\(.\)/_\u/'
Se houver outros sublinhados antes do anterior, então o acima não funcionará.
Se o mês sempre começar com o 8º caractere, use:
sed -e 's/^\(.\{7\}\)\(.\)/\u/'