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

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

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

a="Hi all" 

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

 "hi all" 

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

тр

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

AWK

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

Bash 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 [AZ]) 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 

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

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

tr :

 a="$(tr [AZ] [az] <<< "$a")" 

AWK :

 { print tolower($0) } 

sed :

 y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ 

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

UPPER -> lower : используйте 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` 

Также, когда вы говорите «shell», я предполагаю, что вы имеете в виду 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 

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

 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/(.*)\/([^\/]*)/$1\/\L$2/' {} \; 

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

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

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

Пример:

 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! 

введите описание изображения здесь

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 "${1}"=\'$(echo ${!1//\'/"'\''"} | tr [:upper:] [:lower:] )\' } 

Заметки:

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

Для версий 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 [AZ] ) printf -v __decimal '%d' "'$__char" printf -v __octal '%03o' $(( $__decimal ^ 0x20 )) printf -v __char \\$__octal ;; esac __result+="$__char" done REPLY="$__result" } 

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

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

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

Если вы знаете, что у вас будет ansible 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 чтобы преобразовать число обратно в символ. Из '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 [AZ]) 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 [az]) 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.

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

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

Преобразует весь текст в путь / в / file / filename в диапазоне az до AZ

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

 cat path/to/file/filename | tr 'az' 'AZ' 

Для преобразования от верхнего регистра к нижнему регистру

 cat path/to/file/filename | tr 'AZ' 'az' 

Например,

имя файла:

 my name is xyz 

преобразуется в:

 MY NAME IS XYZ 

Пример 2:

 echo "my name is 123 karthik" | tr 'az' 'AZ' # Output: # MY NAME IS 123 KARTHIK 

Пример 3:

 echo "my name is 123 &&^&& #@$#@%%& kAR2~thik" | tr 'az' 'AZ' # Output: # MY NAME IS 123 &&^&& #@0@%%& KAR2~THIK 

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

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

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

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

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

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

  • 0.46s для моего подхода к нижнему регистру; 0.96s для верхнего регистра
  • 1.16s для подхода Овервелофила к нижнему регистру ; 1.59s для верхнего регистра
  • 3.67s для tr в нижний регистр; 3.81s для верхнего регистра
  • 11.12s для подхода ghostdog74 к нижнему регистру ; 31.41s для верхнего регистра
  • 26.25s для подхода технозавров к нижнему регистру ; 26.21s для верхнего регистра
  • 25.06s для подхода JaredTS486 к нижнему регистру ; 27.04s для верхнего регистра

Сроки для 1000 итераций 445 символов (состоящие из стихотворения «Робин» Уитнера Биннера):

  • 2s для моего подхода к нижнему регистру; 12s для верхнего регистра
  • 4s для tr в нижний регистр; 4s для верхнего регистра
  • 20-е годы для подхода Овервелофила к нижнему регистру ; 29s для верхнего регистра
  • 75s для подхода ghostdog74 к нижнему регистру ; 669s для верхнего регистра. Интересно отметить, насколько сильно разница в производительности между тестом с преобладающими совпадениями против теста с преобладающими промахами
  • 467s для подхода технозавров к нижнему регистру ; 449s для верхнего регистра
  • 660s для подхода 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}" =~ ([AZ]) ]] 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}" =~ ([az]) ]] do LCHAR="${BASH_REMATCH[1]}" LOFFSET="${LCS%%${LCHAR}*}" TARGET="${TARGET//${LCHAR}/${UCS:${#LOFFSET}:1}}" done echo -n "${TARGET}" } 

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

Некоторые характеристики производительности моего решения:

  1. Использует только встроенные утилиты shell, которые позволяют избежать накладных расходов при вызове внешних двоичных утилит в новом процессе
  2. Избегает подclassов, которые несут штрафы за производительность
  3. Использует механизмы оболочки, которые скомпилированы и оптимизированы для производительности, такие как глобальная замена строки внутри переменных, обрезка суффикса переменных и поиск и сопоставление регулярных выражений. Эти механизмы намного быстрее, чем итерация вручную через строки
  4. Циклирует только количество раз, необходимое для подсчета уникальных совпадающих символов для преобразования. Например, преобразование строки с тремя разными прописными буквами в нижний регистр требует только трех итераций цикла. Для предварительно сконфигурированного алфавита ASCII максимальное число итераций цикла составляет 26
  5. UCS и LCS могут быть дополнены дополнительными символами
  • Преобразование строки в дату на C ++
  • Оценка строки "3 * (4 + 2)" yield int 18
  • Возможны ли параметры в strings.xml?
  • Проверьте, является ли строка директором, не исключая исключения?
  • Простой способ повторить строку в java
  • Преобразование в String с использованием ("" + ) плохой практики?
  • Длина строки без использования метода length ()
  • Имеет ли xslt функцию split ()?
  • Почему .NET String неизменяема?
  • Как разбить строку на многосимвольный разделитель на C #?
  • Найти первый повторный символ в строке
  • Давайте будем гением компьютера.