Как преобразовать строку в нижний регистр в Bash?

Есть ли способ в преобразовать строку в строчную строку?

Например, если у меня есть:

a="Hi all"

Я хочу преобразовать его в:

"hi all"

Ответ 1

Существуют различные способы:

Стандарт POSIX

тр

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

AWK

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

Non-POSIX

Вы можете столкнуться с проблемами переносимости в следующих примерах:

Баш 4.0

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

СЕПГ

$ 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]. Bash сбит с толку двойным негативом ("unsetting nocasematch")! :-)

Ответ 2

В 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

Переключить (не документировано, но возможно настраивается во время компиляции)

$ 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.

Ответ 3

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

Ответ 4

tr:

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

AWK:

{ print tolower($0) }

sed:

y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/

Ответ 5

Я знаю, что это старая должность, но я сделал этот ответ для другого сайта, поэтому я подумал, что разместил его здесь:

ВЕРХНИЙ → нижний: используйте python:

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

Или Ruby:

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`

Или Ruby:

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

для верхнего регистра.

Ответ 6

В zsh:

echo $a:u

Надо любить zsh!

Ответ 7

Использование GNU sed:

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

Пример:

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

Ответ 8

Для стандартной оболочки (без багизмов), использующей только встроенные функции:

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}"
}

Ответ 9

Pre Bash 4.0

Bash Опустить случай строки и назначить переменной

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

echo "$VARIABLE"

Ответ 10

В bash 4 вы можете использовать набор

Пример:

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

Ответ 11

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

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

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

Вы можете указать каталог вместо точки (.) после поиска, которая обозначает текущий каталог или полный путь.

Надеюсь, что это решение окажется полезным тем, что эта команда не делает, это заменить пробелы символами подчеркивания - возможно, еще раз.

Ответ 13

При использовании 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} позволяет работать, даже если строка содержит кавычки.

Ответ 14

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

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"
}

ответ technosaurus также имел потенциал, хотя он действительно работал правильно для меня.

Ответ 15

Несмотря на то, насколько старый этот вопрос и похож на этот ответ technosaurus. Мне было трудно найти решение, которое было переносимым на большинстве платформ (это я использую), а также более старые версии bash. Я также был расстроен массивами, функциями и использованием отпечатков, эхо и временных файлов для извлечения тривиальных переменных. Это очень хорошо для меня, я думал, что поделюсь. Моей основной средой тестирования являются:

  • GNU bash, версия 4.1.2 (1) -release (x86_64-redhat-linux-gnu)
  • GNU bash, версия 3.2.57 (1) -release (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}}"

Ответ 16

Многие ответы используют внешние программы, которые на самом деле не используют Bash.

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

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

Как это работает

Как это работает, получая целочисленное представление ASCII каждого char с printf, а затем adding 32, если upper-to->lower, или subtracting 32, если lower-to->upper. Затем снова используйте printf, чтобы преобразовать число обратно в char. Из '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="[email protected]"
    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="[email protected]"
    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 "[email protected]" 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, например.

Ответ 17

Конвертирование происходит только для алфавитов. Итак, это должно работать аккуратно.

Я сосредотачиваюсь на преобразовании алфавитов между 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 &&^&& #@[email protected]%%& KAR2~THIK

Ответ 18

Если вам нравится python и у вас есть возможность установить новый пакет python, вы можете попробовать эту утилиту python.

# install pythonp
$ pip install pythonp

$ echo $a | pythonp "l.lower()"

Ответ 19

Сохранить преобразованную строку в переменную. После работы для меня - $SOURCE_NAME до $TARGET_NAME

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

Ответ 20

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

Я рассчитал 1000 итераций этого подхода для маленькой строки (25 символов) и большей строки (445 символов) как для преобразования в нижний, так и в верхний регистр. Поскольку тестовые строки преимущественно строчные, преобразования в нижний регистр обычно выполняются быстрее, чем в верхний.

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

Вот временные результаты для 1000 итераций по 25 символов:

Результаты синхронизации для 1000 итераций по 445 символов (состоящих из поэмы "Робин" Уиттера Биннера):

  • 2 для моего подхода к строчным буквам; 12с прописными буквами
  • 4s для tr в нижний регистр; 4с прописными буквами
  • 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 могут быть дополнены дополнительными символами