Як перетворити рядок у малі регістри в Bash?


Відповіді:


2180

Існують різні способи:

POSIX стандарт

тр

$ echo "$a" | tr '[:upper:]' '[:lower:]'
hi all

AWK

$ echo "$a" | awk '{print tolower($0)}'
hi all

Non-POSIX

Ви можете зіткнутися з проблемами переносимості за допомогою таких прикладів:

Bash 4.0

$ echo "${a,,}"
hi all

sed

$ echo "$a" | sed -e 's/\(.*\)/\L\1/'
hi all
# this also works:
$ sed -e 's/\(.*\)/\L\1/' <<< "$a"
hi all

Perl

$ echo "$a" | perl -ne 'print lc'
hi all

Баш

lc(){
    case "$1" in
        [A-Z])
        n=$(printf "%d" "'$1")
        n=$((n+32))
        printf \\$(printf "%o" "$n")
        ;;
        *)
        printf "%s" "$1"
        ;;
    esac
}
word="I Love Bash"
for((i=0;i<${#word};i++))
do
    ch="${word:$i:1}"
    lc "$ch"
done

Примітка: YMMV на цьому. Не працює для мене (GNU bash версії 4.2.46 та 4.0.33 (та ж поведінка 2.05b.0, але nocasematch не реалізований)) навіть при використанні shopt -u nocasematch;. Якщо встановити, що nocasematch викликає [["fooBaR" == "FOObar"]] відповідність ОК, але всередині випадку дивно [bz] невірно узгоджено [AZ]. Баш плутає подвійний негатив ("невстановлювальний нокашмат")! :-)


9
Я чогось пропускаю, чи ваш останній приклад (у Bash) насправді робить щось зовсім інше? Він працює для "ABX", але якщо ви замість цього зробите, word="Hi All"як інші приклади, він повертається ha, ні hi all. Він працює лише для великих літер та пропускає літери, які вже є малими літерами.
jangosteve

26
Зауважте, що у стандарті POSIX вказані лише trта awkприклади.
Річард Хансен

178
tr '[:upper:]' '[:lower:]'буде використовувати поточний локал для визначення великих / малих еквівалентів, тому він буде працювати з локалями, які використовують літери з діакритичними позначками.
Річард Хансен

10
Як можна отримати вихід у нову змінну? Тобто, я хочу, щоб рядок нижнього регістру перейшов у нову змінну?
Адам Паркін

60
@Adam:b="$(echo $a | tr '[A-Z]' '[a-z]')"
Тіно

434

У Bash 4:

Для малих літер

$ string="A FEW WORDS"
$ echo "${string,}"
a FEW WORDS
$ echo "${string,,}"
a few words
$ echo "${string,,[AEIUO]}"
a FeW WoRDS

$ string="A Few Words"
$ declare -l string
$ string=$string; echo "$string"
a few words

До верхнього регістру

$ string="a few words"
$ echo "${string^}"
A few words
$ echo "${string^^}"
A FEW WORDS
$ echo "${string^^[aeiou]}"
A fEw wOrds

$ string="A Few Words"
$ declare -u string
$ string=$string; echo "$string"
A FEW WORDS

Toggle (недокументований, але необов'язково налаштовується під час компіляції)

$ string="A Few Words"
$ echo "${string~~}"
a fEW wORDS
$ string="A FEW WORDS"
$ echo "${string~}"
a FEW WORDS
$ string="a few words"
$ echo "${string~}"
A few words

Великі літери (недокументовані, але необов'язково налаштовуються під час компіляції)

$ string="a few words"
$ declare -c string
$ string=$string
$ echo "$string"
A few words

Заголовок справи:

$ string="a few words"
$ string=($string)
$ string="${string[@]^}"
$ echo "$string"
A Few Words

$ declare -c string
$ string=(a few words)
$ echo "${string[@]}"
A Few Words

$ string="a FeW WOrdS"
$ string=${string,,}
$ string=${string~}
$ echo "$string"
A few words

Щоб вимкнути declareатрибут, використовуйте +. Наприклад, declare +c string. Це впливає на наступні призначення, а не на поточне значення.

В declareопції змінити атрибут змінної, але не вміст. Переназначення в моїх прикладах оновлює вміст, щоб показати зміни.

Редагувати:

Додано "перемикання першого символу за словом" ( ${var~}), як запропонував ghostdog74 .

Редагувати: виправлена ​​поведінка тильди, щоб відповідати Bash 4.3.


5
Досить Bizzare, "^^" і ",," оператори не працюють над символами, що не належать до ASCII, але "~~" робить ... Так string="łódź"; echo ${string~~}повернеться "ŁÓDŹ", але echo ${string^^}поверне "łóDź". Навіть в LC_ALL=pl_PL.utf-8. Для цього використовується bash 4.2.24.
Хуберт Каріо

2
@HubertKario: Це дивно. Для мене це те саме в Bash 4.0.33 з тією ж строкою в en_US.UTF-8. Це помилка, і я повідомив про це.
Призупинено до подальшого повідомлення.

1
@HubertKario: Спробуйте echo "$string" | tr '[:lower:]' '[:upper:]'. Це, мабуть, виявить такий самий збій. Тож проблема, принаймні, частково не у Баша.
Призупинено до подальшого повідомлення.

1
@DennisWilliamson: Так, я теж помітив це (див. Коментар до відповіді Шувалова). Я просто сказав, "цей матеріал призначений лише для ASCII", але тоді оператор "~~" працює, тому це не так, як таблиці кодів і переклади вже не існують ...
Hubert Kario

4
@HubertKario: Підтримка Bash визнала помилку і заявила, що вона буде виправлена ​​в наступному випуску.
Призупинено до подальшого повідомлення.

123
echo "Hi All" | tr "[:upper:]" "[:lower:]"

4
@RichardHansen: trне працює для мене з персонажами, які не є ACII. У мене є правильний набір локалів та створені файли локалів. Маєте якусь ідею, що я можу зробити неправильно?
Хуберт Каріо

FYI: Це працювало на Windows / Msys. Деякі з інших пропозицій цього не зробили.
wasatchwizard

3
Навіщо це [:upper:]потрібно?
mgutt

77

tr :

a="$(tr [A-Z] [a-z] <<< "$a")"

AWK :

{ print tolower($0) }

sed :

y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/

2
+1 a="$(tr [A-Z] [a-z] <<< "$a")"мені виглядає найпростіше. Я все ще початківець ...
Sandeepan Nath

2
Я настійно рекомендую sedрішення; Я працюю в середовищі, якого з якихось причин немає, trале я все ще не знаходжу систему без цього sed, а також багато часу хочу зробити це, я просто все- sedтаки зробив щось інше, так що я можу створити ланцюг команди разом в єдиний (довгий) оператор.
Харавік

2
Виразні дужки повинні бути вказані. В tr [A-Z] [a-z] Aоболонці оболонка може виконувати розширення імені файлів, якщо є імена файлів, що складаються з однієї літери або встановлено nullgob . tr "[A-Z]" "[a-z]" Aбуде вести себе належним чином.
Денніс

2
@CamiloMartin - це система BusyBox, де я маю цю проблему, зокрема Synology NASes, але я стикався з нею і в кількох інших системах. Останнім часом я багато робив сценарії оболонок міжплатформних оболонок, і з вимогою нічого додаткового не встановлювати, це робить речі дуже складними! Однак я ще не стикаюся з системою безsed
Харавік

2
Зверніть увагу, що tr [A-Z] [a-z]це невірно майже у всіх локалях. наприклад, у en-USлокалі - A-Zце фактично інтервал AaBbCcDdEeFfGgHh...XxYyZ.
fuz

44

Я знаю, що це стародавній пост, але я відповів на інший сайт, тому подумав, що опублікую його тут:

Вгору -> нижче : використовувати python:

b=`echo "print '$a'.lower()" | python`

Або Рубі:

b=`echo "print '$a'.downcase" | ruby`

Або Perl (певно, мій улюблений):

b=`perl -e "print lc('$a');"`

Або PHP:

b=`php -r "print strtolower('$a');"`

Або Awk:

b=`echo "$a" | awk '{ print tolower($1) }'`

Або Sed:

b=`echo "$a" | sed 's/./\L&/g'`

Або Bash 4:

b=${a,,}

Або NodeJS, якщо у вас є (і трохи горіхи ...):

b=`echo "console.log('$a'.toLowerCase());" | node`

Ви також можете використовувати dd(але я цього не хочу!):

b=`echo "$a" | dd  conv=lcase 2> /dev/null`

нижня -> ВИПАДКА :

використовувати python:

b=`echo "print '$a'.upper()" | python`

Або Рубі:

b=`echo "print '$a'.upcase" | ruby`

Або Perl (певно, мій улюблений):

b=`perl -e "print uc('$a');"`

Або PHP:

b=`php -r "print strtoupper('$a');"`

Або Awk:

b=`echo "$a" | awk '{ print toupper($1) }'`

Або Sed:

b=`echo "$a" | sed 's/./\U&/g'`

Або Bash 4:

b=${a^^}

Або NodeJS, якщо у вас є (і трохи горіхи ...):

b=`echo "console.log('$a'.toUpperCase());" | node`

Ви також можете використовувати dd(але я цього не хочу!):

b=`echo "$a" | dd  conv=ucase 2> /dev/null`

Також, коли ви говорите "оболонка", я припускаю, що ви маєте на увазі, bashале якщо ви можете використовувати zshце так просто

b=$a:l

для малих і

b=$a:u

для верхнього регістру.


@JESii обидва працюють для мене верхній -> нижній і нижній-> верхній. Я використовую sed 4.2.2 та Bash 4.3.42 (1) на 64-розрядному Debian Stretch.
nettux

1
Привіт! Я перебуваю на OSX, використовуючи bash homebrew: GNU bash, версія 4.3.42 (1) -release (x86_64-apple-darwin14.5.0)
JESii

5
Не використовувати! Усі приклади, які генерують сценарій, надзвичайно крихкі; якщо значення aмістить одну цитату, у вас є не тільки порушена поведінка, але й серйозна проблема безпеки.
трійка

Мені найбільше подобається розчин sed, оскільки sed завжди є всюдисущим.
Дуді Хлопчик

Я вважаю за краще використовувати рішення DD. Зверніть увагу, що вам потрібно мати root, щоб він працював
inetphantom


18

Використання GNU sed:

sed 's/.*/\L&/'

Приклад:

$ foo="Some STRIng";
$ foo=$(echo "$foo" | sed 's/.*/\L&/')
$ echo "$foo"
some string

12

Pre Bash 4.0

Bash Опустити регістр рядка і призначити змінній

VARIABLE=$(echo "$VARIABLE" | tr '[:upper:]' '[:lower:]') 

echo "$VARIABLE"

5
Не потрібно echoі труби: використання$(tr '[:upper:]' '[:lower:]' <<<"$VARIABLE")
Тіно

3
@Tino Цей рядок також не є портативним назад до дійсно старих версій Bash; Я вважаю, що він був представлений у v3.
трійка

1
@tripleee Ви маєте рацію, вона була введена в bash-2.05b - проте це найдавніший баш, який я зміг знайти в своїх системах
Tino

11

Для стандартної оболонки (без башизмів) використовують лише вбудовані:

uppers=ABCDEFGHIJKLMNOPQRSTUVWXYZ
lowers=abcdefghijklmnopqrstuvwxyz

lc(){ #usage: lc "SOME STRING" -> "some string"
    i=0
    while ([ $i -lt ${#1} ]) do
        CUR=${1:$i:1}
        case $uppers in
            *$CUR*)CUR=${uppers%$CUR*};OUTPUT="${OUTPUT}${lowers:${#CUR}:1}";;
            *)OUTPUT="${OUTPUT}$CUR";;
        esac
        i=$((i+1))
    done
    echo "${OUTPUT}"
}

А для верхнього регістру:

uc(){ #usage: uc "some string" -> "SOME STRING"
    i=0
    while ([ $i -lt ${#1} ]) do
        CUR=${1:$i:1}
        case $lowers in
            *$CUR*)CUR=${lowers%$CUR*};OUTPUT="${OUTPUT}${uppers:${#CUR}:1}";;
            *)OUTPUT="${OUTPUT}$CUR";;
        esac
        i=$((i+1))
    done
    echo "${OUTPUT}"
}

Цікаво, якщо ви не впустили башизму в цьому сценарії, оскільки він не переноситься на FreeBSD sh: $ {1: $ ...}: Погана заміна
Дерексон

2
Дійсно; підрядки з ${var:1:1}- це башизм.
трійчатка

Цей підхід має досить погані показники ефективності. Дивіться мою відповідь щодо показників.
Dejay Clayton

9

У bash 4 можна використовувати набір

Приклад:

A="HELLO WORLD"
typeset -l A=$A


7

Регулярне вираження

Я хотів би взяти подяку за команду, яку хочу поділитися, але правда, я отримав її для власного використання від http://commandlinefu.com . Перевагою є те, що якщо ви перейдете cdдо будь-якого каталогу у вашій власній домашній папці, то це змінить усі файли та папки на малі рекурсивно, будь ласка, використовуйте з обережністю. Це блискуче виправлення командного рядка і особливо корисне для тих наборів альбомів, які ви зберегли на диску.

find . -depth -exec rename 's/(.*)\/([^\/]*)/$1\/\L$2/' {} \;

Ви можете вказати каталог замість крапки (.) Після знаходження, що позначає поточний каталог або повний шлях.

Я сподіваюсь, що це рішення виявиться корисним. Єдине, що ця команда не робить, це замінити пробіли на підкреслення - ну, можливо, інший раз.


Це не спрацювало для мене з будь-якої причини, хоча це виглядає чудово. Я все-таки змусив це працювати як альтернатива: знайти. -exec / bin / bash -c 'mv {} `tr [AZ] [az] <<< {}`' \;
Джон Рікс

Це потрібно prenameвід perl: dpkg -S "$(readlink -e /usr/bin/rename)"даєperl: /usr/bin/prename
Тіно

4

Багато відповідей за допомогою зовнішніх програм, які насправді не використовуються Bash.

Якщо ви знаєте, що у вас буде доступний Bash4, вам слід просто скористатися ${VAR,,}позначеннями (це легко і круто). Для Bash до 4 (наприклад, у My Mac все ще використовується Bash 3.2). Я використав виправлену версію відповіді @ ghostdog74, щоб створити більш портативну версію.

Ви можете зателефонувати lowercase 'my STRING'та отримати малу версію. Я читав коментарі щодо налаштування результату на var, але це не дуже портативно Bash, оскільки ми не можемо повернути рядки. Друк - найкраще рішення. Легко захопити чимось подібним var="$(lowercase $str)".

Як це працює

Як це працює, отримуючи ціле представлення ASCII кожного знака з, printfа потім, adding 32якщо upper-to->lowerабо subtracting 32якщо lower-to->upper. Потім printfзнову використовуйте, щоб перетворити число назад у знак. Від 'A' -to-> 'a'нас є різниця 32 символи.

Використовуючи printfдля пояснення:

$ printf "%d\n" "'a"
97
$ printf "%d\n" "'A"
65

97 - 65 = 32

І це робоча версія з прикладами.
Будь ласка, зверніть увагу на коментарі до коду, оскільки вони пояснюють багато речей:

#!/bin/bash

# lowerupper.sh

# Prints the lowercase version of a char
lowercaseChar(){
    case "$1" in
        [A-Z])
            n=$(printf "%d" "'$1")
            n=$((n+32))
            printf \\$(printf "%o" "$n")
            ;;
        *)
            printf "%s" "$1"
            ;;
    esac
}

# Prints the lowercase version of a sequence of strings
lowercase() {
    word="$@"
    for((i=0;i<${#word};i++)); do
        ch="${word:$i:1}"
        lowercaseChar "$ch"
    done
}

# Prints the uppercase version of a char
uppercaseChar(){
    case "$1" in
        [a-z])
            n=$(printf "%d" "'$1")
            n=$((n-32))
            printf \\$(printf "%o" "$n")
            ;;
        *)
            printf "%s" "$1"
            ;;
    esac
}

# Prints the uppercase version of a sequence of strings
uppercase() {
    word="$@"
    for((i=0;i<${#word};i++)); do
        ch="${word:$i:1}"
        uppercaseChar "$ch"
    done
}

# The functions will not add a new line, so use echo or
# append it if you want a new line after printing

# Printing stuff directly
lowercase "I AM the Walrus!"$'\n'
uppercase "I AM the Walrus!"$'\n'

echo "----------"

# Printing a var
str="A StRing WITH mixed sTUFF!"
lowercase "$str"$'\n'
uppercase "$str"$'\n'

echo "----------"

# Not quoting the var should also work, 
# since we use "$@" inside the functions
lowercase $str$'\n'
uppercase $str$'\n'

echo "----------"

# Assigning to a var
myLowerVar="$(lowercase $str)"
myUpperVar="$(uppercase $str)"
echo "myLowerVar: $myLowerVar"
echo "myUpperVar: $myUpperVar"

echo "----------"

# You can even do stuff like
if [[ 'option 2' = "$(lowercase 'OPTION 2')" ]]; then
    echo "Fine! All the same!"
else
    echo "Ops! Not the same!"
fi

exit 0

І результати після цього:

$ ./lowerupper.sh 
i am the walrus!
I AM THE WALRUS!
----------
a string with mixed stuff!
A STRING WITH MIXED STUFF!
----------
a string with mixed stuff!
A STRING WITH MIXED STUFF!
----------
myLowerVar: a string with mixed stuff!
myUpperVar: A STRING WITH MIXED STUFF!
----------
Fine! All the same!

Це має працювати лише для символів ASCII .

Для мене це добре, оскільки я знаю, що передаю йому лише символи ASCII.
Наприклад, я використовую це для деяких нечутливих до випадків варіантів CLI.


4

Перетворення корпусу робиться лише для алфавітів. Отже, це повинно працювати акуратно.

Я зосереджуюсь на перетворенні алфавітів між az з верхнього регістру в нижній регістр. Будь-які інші символи повинні бути просто надруковані у stdout, як це є ...

Перетворює весь текст у шляху / до / файлу / імені файла в діапазоні az до AZ

Для перетворення нижнього регістру у верхній регістр

cat path/to/file/filename | tr 'a-z' 'A-Z'

Для перетворення з верхнього регістру в нижній регістр

cat path/to/file/filename | tr 'A-Z' 'a-z'

Наприклад,

ім'я файлу:

my name is xyz

перетворюється на:

MY NAME IS XYZ

Приклад 2:

echo "my name is 123 karthik" | tr 'a-z' 'A-Z'
# Output:
# MY NAME IS 123 KARTHIK

Приклад 3:

echo "my name is 123 &&^&& #@$#@%%& kAR2~thik" | tr 'a-z' 'A-Z'
# Output:
# MY NAME IS 123 &&^&& #@0@%%& KAR2~THIK

3

Якщо використовується v4, це вбудована версія . Якщо ні, ось просте, широко застосовуване рішення. Інші відповіді (та коментарі) на цю тему були дуже корисними для створення коду нижче.

# Like echo, but converts to lowercase
echolcase () {
    tr [:upper:] [:lower:] <<< "${*}"
}

# Takes one arg by reference (var name) and makes it lowercase
lcase () { 
    eval "${1}"=\'$(echo ${!1//\'/"'\''"} | tr [:upper:] [:lower:] )\'
}

Примітки:

  • Виконання: a="Hi All"і тоді: lcase aзробить те саме, що і:a=$( echolcase "Hi All" )
  • У функції lcase, використання ${!1//\'/"'\''"}замість цього ${!1}дозволяє це працювати навіть тоді, коли рядок має лапки.

3

Для версій Bash раніше, ніж 4.0, ця версія повинна бути найшвидшою (оскільки вона не розщеплює / не виконує жодних команд):

function string.monolithic.tolower
{
   local __word=$1
   local __len=${#__word}
   local __char
   local __octal
   local __decimal
   local __result

   for (( i=0; i<__len; i++ ))
   do
      __char=${__word:$i:1}
      case "$__char" in
         [A-Z] )
            printf -v __decimal '%d' "'$__char"
            printf -v __octal '%03o' $(( $__decimal ^ 0x20 ))
            printf -v __char \\$__octal
            ;;
      esac
      __result+="$__char"
   done
   REPLY="$__result"
}

Відповідь технозавра теж мав потенціал, хоча він працював належним чином для мене.


Непогано! Для аналізу ефективності цього підходу, будь ласка, дивіться мою відповідь щодо показників.
Dejay Clayton

3

Незважаючи на те, скільки років це питання, і подібний на цю відповідь технозавр . Мені важко було знайти рішення, яке було портативним на більшості платформ (That I Use), а також у старих версіях bash. Мене також розчарували масиви, функції та використання відбитків, ехо та тимчасових файлів для пошуку тривіальних змінних. Це дуже добре працює для мене, поки я думав, що поділюсь. Мої основні середовища тестування:

  1. GNU bash, версія 4.1.2 (1) -випуск (x86_64-redhat-linux-gnu)
  2. GNU bash, версія 3.2.57 (1) -випуск (sparc-sun-solaris2.10)
lcs="abcdefghijklmnopqrstuvwxyz"
ucs="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
input="Change Me To All Capitals"
for (( i=0; i<"${#input}"; i++ )) ; do :
    for (( j=0; j<"${#lcs}"; j++ )) ; do :
        if [[ "${input:$i:1}" == "${lcs:$j:1}" ]] ; then
            input="${input/${input:$i:1}/${ucs:$j:1}}" 
        fi
    done
done

Простий стиль C для циклу, який можна повторити через рядки. Для рядка нижче, якщо ви ще нічого подібного не бачили, саме тут я дізнався це . У цьому випадку рядок перевіряє, чи існує char $ {input: $ i: 1} (нижній регістр), і якщо так, замінює його на даний char $ {ucs: $ j: 1} (верхній регістр) та зберігає його назад у вхід.

input="${input/${input:$i:1}/${ucs:$j:1}}"

Це дико неефективно, циклічно зациклившись у вашому прикладі вище 650 разів та зайнявши 35 секунд для виконання 1000 викликів на моїй машині. Для альтернативи, яка циклічно виконує лише 11 разів та займає менше 5 секунд, щоб виконати 1000 викликів, дивіться мою альтернативну відповідь.
Dejay Clayton

1
Дякую, хоча це повинно бути очевидним лише з того, що дивитись на це. Можливо, помилки сторінки пов'язані з розміром введення та кількістю повторень, які ви виконуєте. Тим не менш мені подобається ваше рішення.
JaredTS486

3

Це набагато швидший варіант підходу JaredTS486, який використовує вбудовані можливості Bash (включаючи версії Bash <4.0) для оптимізації його підходу.

Я присвятив 1000 ітерацій цього підходу для невеликої рядка (25 символів) і більшої рядки (445 символів), як для малих, так і для великих рейтингів. Оскільки рядки тестування мають переважно малі літери, перетворення в малі регістри, як правило, швидше, ніж у великі.

Я порівняв свій підхід з кількома іншими відповідями на цій сторінці, сумісними з Bash 3.2. Мій підхід набагато ефективніший, ніж більшість підходів, зафіксованих тут, і навіть швидший, ніж trу кількох випадках.

Ось результати синхронізації для 1000 ітерацій 25 символів:

  • 0,46 за мій підхід до малих літер; 0,96 для великої літери
  • 1,16 за підхід Орвелофіла до малих літер; 1,59 для великих літер
  • 3,67 для trмалої літери; 3,81s для великих літер
  • 11.12s для підходу ghostdog74 до малих літер; 31,41 для великої літери
  • 26,25s для підходу технозавра до малих літер; 26,21 для великої літери
  • 25.06 за підхід JaredTS486 до малих літер; 27,04 для великої літери

Результати часу для 1000 ітерацій 445 символів (що складаються з поеми Віттера Байннера "Робін"):

  • 2s за мій підхід до малих літер; 12 з великої літери
  • 4s для trмалих літер; 4s для великих літер
  • 20-ті роки для підходу Орвелофіла до малих літер; 29 з великої літери
  • 75 років для підходу ghostdog74 до малих літер; 669 для великих літер. Цікаво відзначити, наскільки драматична різниця у виконанні між тестом з переважними матчами порівняно з тестом з переважними пропусками
  • 467 для підходу технозавра до малих літер; 449 для великих літер
  • 660-ті роки для підходу JaredTS486 до малих літер; 660 з великої літери. Цікаво відзначити, що такий підхід генерував у Bash постійні помилки сторінки (заміна пам'яті)

Рішення:

#!/bin/bash
set -e
set -u

declare LCS="abcdefghijklmnopqrstuvwxyz"
declare UCS="ABCDEFGHIJKLMNOPQRSTUVWXYZ"

function lcase()
{
  local TARGET="${1-}"
  local UCHAR=''
  local UOFFSET=''

  while [[ "${TARGET}" =~ ([A-Z]) ]]
  do
    UCHAR="${BASH_REMATCH[1]}"
    UOFFSET="${UCS%%${UCHAR}*}"
    TARGET="${TARGET//${UCHAR}/${LCS:${#UOFFSET}:1}}"
  done

  echo -n "${TARGET}"
}

function ucase()
{
  local TARGET="${1-}"
  local LCHAR=''
  local LOFFSET=''

  while [[ "${TARGET}" =~ ([a-z]) ]]
  do
    LCHAR="${BASH_REMATCH[1]}"
    LOFFSET="${LCS%%${LCHAR}*}"
    TARGET="${TARGET//${LCHAR}/${UCS:${#LOFFSET}:1}}"
  done

  echo -n "${TARGET}"
}

Підхід простий: тоді як у рядку введення є всі інші великі літери, знайдіть наступний і замініть всі екземпляри цієї літери на її малі варіанти. Повторіть, поки не заміняться всі великі літери.

Деякі характеристики мого рішення:

  1. Використовує лише вбудовані у оболонки утиліти, що дозволяє уникнути накладних витрат на зовнішні бінарні утиліти у новому процесі
  2. Уникайте суб-снарядів, які несуть штрафи за продуктивність
  3. Використовує механізми оболонки, які компілюються та оптимізовані для продуктивності, такі як глобальна заміна рядків у межах змінних, обрізка суффіксів змінних та пошук та узгодження регексу. Ці механізми набагато швидше, ніж ітерація вручну через рядки
  4. Цикли лише кількість разів, необхідну для підрахунку унікальних відповідних символів для перетворення. Наприклад, для перетворення рядка з трьома різними символами у малі регістри потрібні лише 3 ітерації циклу. Для попередньо налаштованого алфавіту ASCII максимальна кількість ітерацій циклу - 26
  5. UCSі LCSможна доповнити додатковими символами

2

Для зберігання перетвореного рядка у змінну. Слідом працював для мене - $SOURCE_NAME до$TARGET_NAME

TARGET_NAME="`echo $SOURCE_NAME | tr '[:upper:]' '[:lower:]'`"

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.