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

есть ли способ в Баш чтобы преобразовать строку в строку нижнего регистра?

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

a="Hi all"

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

"hi all"

19 ответов


различные способы:

POSIX standard

tr

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

на awk

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

Non-POSIX

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

Bash 4.0

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

sed

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

Perl

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

Баш

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

В 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

Capitalize (недокументированный, но необязательно настраиваемый во время компиляции)

$ 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

выключить


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

tr:

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

на awk:

{ print tolower() }

sed:

y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/

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

верхний -> нижний: использовать 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() }'`

Или 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() }'`

Или 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

в верхнем регистре.


в zsh:

echo $a:u

должен любить zsh!


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

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

пример:

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

для стандартной оболочкой (без bashisms), используя только примитивы:

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

Pre Bash 4.0

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

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

echo "$VARIABLE"

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

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

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

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

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


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

пример:

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

вы можете попробовать это

s="Hello World!" 

echo $s  # Hello World!

a=${s,,}
echo $a  # hello world!

b=${s^^}
echo $b  # HELLO WORLD!

enter image description here

ref : http://wiki.workassis.com/shell-script-convert-text-to-lowercase-and-uppercase/


если используется v4, это запеченные-в. Если нет, вот простой, широко применяется решение. Другие ответы (и комментарии) по этой теме были весьма полезны при создании кода ниже.

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

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

Примечания:

  • делаем: a="Hi All" и затем: lcase a будет делать то же самое, что: a=$( echolcase "Hi All" )
  • в функции lcase, используя ${!1//\'/"'\''"} вместо ${!1} позволяет этому работать, даже если строка имеет двойные кавычки.

для версий Bash ранее 4.0 эта версия должна быть самой быстрой (так как она не вилка / exec любой команды):

function string.monolithic.tolower
{
   local __word=
   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 это также имел потенциал, хотя он работал должным образом для mee.


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

  1. GNU bash, начиная с версии 4.1.2(1)-релиз (архитектуру x86_64-RedHat это-линукс-гну)
  2. 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}}"

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

если вы знаете, что у вас будет bash4, вы должны просто использовать ${VAR,,} нотации (это легко и круто). Для Bash до 4 (мой 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 снова преобразовывать число обратно в 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 "" in
        [A-Z])
            n=$(printf "%d" "'")
            n=$((n+32))
            printf \$(printf "%o" "$n")
            ;;
        *)
            printf "%s" ""
            ;;
    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 "" in
        [a-z])
            n=$(printf "%d" "'")
            n=$((n-32))
            printf \$(printf "%o" "$n")
            ;;
        *)
            printf "%s" ""
            ;;
    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 без учета регистра, например.


преобразование дело делается только для алфавитов. Так что это должно сработать аккуратно.

Я сосредоточен на преобразовании алфавитов между a-z из верхнего регистра в нижний регистр. Любые другие символы должны быть напечатаны в stdout, как это...

преобразует весь текст в path / to / file / filename в диапазоне a-z в A-Z

для преобразования нижнего регистра в верхний регистр

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

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

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

это гораздо более быстрый вариант JaredTS486 это который использует собственные возможности Bash (включая версии Bash

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

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

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

  • 0.46 s для моего подхода к строчному регистру; 0.96 s для верхнего регистра
  • 1.16 s для Orwellophile это в нижний регистр; 1.59 S для прописные
  • 3,67 С для tr в нижний регистр; 3,81 С для верхнего регистра
  • 11.12 s для ghostdog74 это в нижнем регистре; 31.41 s для верхнего регистра
  • 26.25 s для technosaurus' в нижнем регистре; 26.21 s для верхнего регистра
  • 25.06 s для JaredTS486 это в нижнем регистре; 27.04 s для верхнего регистра

результаты синхронизации для 1,000 итераций 445 символов (состоящих из стихотворения "The Robin" by Witter Bynner):

  • 2s для моего подхода к строчному регистру; 12s для верхнего регистра
  • 4s для tr в нижний регистр; 4s для верхнего регистра
  • 20s для Orwellophile это в нижнем регистре; 29s для верхнего регистра
  • 75-й для ghostdog74 это подход к строчным буквам; 669s для верхнего регистра. Интересно отметить, насколько драматична разница в производительности между тестом с преобладающими совпадениями и тестом с преобладающие промахи
  • 467s для technosaurus' в нижнем регистре; 449s для верхнего регистра
  • 660-е годы для JaredTS486 это в нижнем регистре; 660s для верхнего регистра. Интересно отметить, что этот подход генерировал непрерывные ошибки страницы (обмен памятью) в 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. использует только утилиты Shell builtin, что позволяет избежать накладных расходов на вызов внешних двоичных утилит в новом процессе
  2. избегает суб-оболочек, которые несут штрафы за производительность
  3. использует механизмы оболочки, которые скомпилированы и оптимизированы для производительности, такие как глобальная замена строк в переменных, обрезка суффиксов переменных и поиск и сопоставление регулярных выражений. Эти механизмы намного быстрее, чем итерация вручную через строки
  4. циклы только количество раз, требуемое количеством уникальных совпадающих символов для преобразования. Например, преобразование строки с тремя разными символами верхнего регистра в нижний регистр требует только 3 итераций цикла. Для предварительно настроенного алфавита ASCII максимальное число итераций цикла это 26
  5. UCS и LCS можно дополнить дополнительными символами