awk или sed в нижнем / верхнем регистре только один символ в строке?


13

Есть ли способ, как в верхнем / нижнем регистре только один символ в некоторой строке?

Пример ввода:

syslog_apr_24_30
syslog_mar_01_17

Желаемый вывод:

syslog_Apr_24_30
syslog_Mar_01_17

Обратите внимание, пожалуйста, на верхний регистр начала месяца.

Я пытался, awkно я не достаточно хорош, чтобы заставить его работать.

Ответы:


18

Вы можете использовать \uв GNU sed прописные буквы:

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

Perl делает то же самое:

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

\l делает обратное.


8
Немного проще:sed 's/_./\U&/'
Гленн Джекман


3

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

Вот подход 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, используя регулярное выражение для выбора части, которую вы хотите выделить, и ^^оператора upcase для этой части. Прикрепление спереди и сзади (соответствует. *) Для воссоздания всей строки:

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&/')"(опубликовано в качестве комментария к принятому ответу, Гленн Джекман).

Bash, Sed или WKK будет во много раз быстрее, чем Perl. Если вы начинаете находить несколько perl-однострочников полезными в сценарии оболочки, вам просто нужно написать все это на perl.


0

Если месяц всегда следует за первым «_» (подчеркивание), используйте это (как показано в других ответах):

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

Если перед предыдущим месяцем могут быть другие подчеркивания, то вышеприведенное не сработает.

Если месяц всегда начинается с 8-го символа, используйте это:

sed -e 's/^\(.\{7\}\)\(.\)/\1\u\2/'
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.