Ответы:
Существуют различные способы:
$ echo "$a" | tr '[:upper:]' '[:lower:]'
hi all
$ echo "$a" | awk '{print tolower($0)}'
hi all
Вы можете столкнуться с проблемами переносимости в следующих примерах:
$ echo "${a,,}"
hi all
$ echo "$a" | sed -e 's/\(.*\)/\L\1/'
hi all
# this also works:
$ sed -e 's/\(.*\)/\L\1/' <<< "$a"
hi all
$ 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»)! :-)
word="Hi All"
как другие примеры, он вернется ha
, а не hi all
. Он работает только для заглавных букв и пропускает буквы в нижнем регистре.
tr
и awk
примеры указаны в стандарте POSIX.
tr '[:upper:]' '[:lower:]'
будет использовать текущую локаль для определения эквивалентов в верхнем и нижнем регистре, поэтому она будет работать с локалями, которые используют буквы с диакритическими знаками.
b="$(echo $a | tr '[A-Z]' '[a-z]')"
В 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.
string="łódź"; echo ${string~~}
что вернет «ŁÓDŹ», но echo ${string^^}
вернет «łóDź». Даже в LC_ALL=pl_PL.utf-8
. Это использует Bash 4.2.24.
en_US.UTF-8
. Это ошибка, и я сообщил об этом.
echo "$string" | tr '[:lower:]' '[:upper:]'
. Это, вероятно, будет демонстрировать ту же ошибку. Так что проблема, по крайней мере, частично не в Баше.
echo "Hi All" | tr "[:upper:]" "[:lower:]"
tr
у меня не работает персонажи не-ACII. У меня есть правильный набор локали и сгенерированные файлы локали. Есть идеи, что я могу делать не так?
[:upper:]
нужен?
a="$(tr [A-Z] [a-z] <<< "$a")"
{ print tolower($0) }
y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
a="$(tr [A-Z] [a-z] <<< "$a")"
выглядит проще всего для меня. Я все еще новичок ...
sed
решение; Я работал в среде, которая по какой-то причине отсутствует, tr
но я еще не нашел систему без нее sed
, плюс большую часть времени я хочу сделать это, я просто сделал что-то еще в sed
любом случае, так что можно связать команды объединяются в одно (длинное) утверждение.
tr [A-Z] [a-z] A
, оболочка может выполнять расширение имени файла, если есть имена файлов, состоящие из одной буквы или установлен нуль-гоб . tr "[A-Z]" "[a-z]" A
будет вести себя правильно.
sed
tr [A-Z] [a-z]
это неправильно почти во всех локалях. например, в en-US
локали A-Z
фактически указан интервал AaBbCcDdEeFfGgHh...XxYyZ
.
Я знаю, что это старое сообщение, но я сделал этот ответ для другого сайта, поэтому я решил опубликовать его здесь:
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) }'`
Или сед:
b=`echo "$a" | sed 's/./\L&/g'`
Или Баш 4:
b=${a,,}
Или NodeJS, если он у вас есть (и немного чокнутый ...):
b=`echo "console.log('$a'.toLowerCase());" | node`
Вы также можете использовать dd
(но я бы не стал!):
b=`echo "$a" | dd conv=lcase 2> /dev/null`
понизить -> ВЕРХНЯЯ :
использовать питон:
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) }'`
Или сед:
b=`echo "$a" | sed 's/./\U&/g'`
Или Баш 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
для верхнего регистра.
a
содержит одинарную кавычку, у вас есть не только нарушенное поведение, но и серьезная проблема безопасности.
В зш:
echo $a:u
Должен любить Zsh!
echo ${(C)a} #Upcase the first char only
Pre Bash 4.0
Bash Нижний регистр строки и присвоение переменной
VARIABLE=$(echo "$VARIABLE" | tr '[:upper:]' '[:lower:]')
echo "$VARIABLE"
echo
и труб: использовать$(tr '[:upper:]' '[:lower:]' <<<"$VARIABLE")
Для стандартной оболочки (без ошибок) используются только встроенные функции:
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}"
}
${var:1:1}
являются Bashism.
Вы можете попробовать это
s="Hello World!"
echo $s # Hello World!
a=${s,,}
echo $a # hello world!
b=${s^^}
echo $b # HELLO WORLD!
ссылка: http://wiki.workassis.com/shell-script-convert-text-to-lowercase-and-uppercase/
Я хотел бы взять кредит на команду, которой хочу поделиться, но правда в том, что я получил ее для собственного использования на http://commandlinefu.com . Преимущество заключается в том, что если вы cd
перейдете в какой-либо каталог в своей собственной домашней папке, то есть рекурсивно измените все файлы и папки на строчные, пожалуйста, используйте их с осторожностью. Это великолепное исправление командной строки, особенно полезное для множества альбомов, которые вы сохранили на своем диске.
find . -depth -exec rename 's/(.*)\/([^\/]*)/$1\/\L$2/' {} \;
Вы можете указать каталог вместо точки (.) После поиска, которая обозначает текущий каталог или полный путь.
Я надеюсь, что это решение окажется полезным, но единственная вещь, которую не выполняет эта команда, - это заменить пробелы подчеркиванием - ну, в другой раз, возможно.
prename
от perl
: dpkg -S "$(readlink -e /usr/bin/rename)"
даетperl: /usr/bin/prename
Многие ответы используют внешние программы, которые на самом деле не используются Bash
.
Если вы знаете, что у вас будет Bash4, вы должны просто использовать ${VAR,,}
нотацию (это легко и круто). Для Bash до 4 (Мой Mac все еще использует Bash 3.2, например). Я использовал исправленную версию ответа @ ghostdog74, чтобы создать более переносимую версию.
Один вы можете позвонить lowercase 'my STRING'
и получить строчную версию. Я читал комментарии об установке результата в переменную, но он не очень переносим Bash
, поскольку мы не можем возвращать строки. Печать это лучшее решение. Легко захватить с чем-то вроде var="$(lowercase $str)"
.
Как это работает
Это работает путем получения целочисленного представления ASCII каждого символа с printf
и затем adding 32
if upper-to->lower
или subtracting 32
if 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 без учета регистра, например.
Конвертирование происходит только для алфавитов. Итак, это должно работать аккуратно.
Я сосредотачиваюсь на преобразовании алфавитов между 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
При использовании 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" )
${!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
[A-Z] )
printf -v __decimal '%d' "'$__char"
printf -v __octal '%03o' $(( $__decimal ^ 0x20 ))
printf -v __char \\$__octal
;;
esac
__result+="$__char"
done
REPLY="$__result"
}
Ответ технозавра тоже имел потенциал, хотя для меня он действовал правильно.
Несмотря на то, сколько лет этот вопрос и похож на этот ответ технозавра . Мне было трудно найти решение, которое было бы переносимым на большинство платформ (которые я использую), а также на старые версии bash. Я также был разочарован массивами, функциями и использованием распечаток, эхо и временных файлов для получения тривиальных переменных. Это работает очень хорошо для меня, пока я думал, что поделюсь. Мои основные тестовые среды:
- GNU bash, версия 4.1.2 (1) -релиз (x86_64-redhat-linux-gnu)
- 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-стиль для цикла, чтобы перебрать строки. Для строки ниже, если вы не видели ничего подобного до этого, я узнал об этом . В этом случае строка проверяет, существует ли на входе символ $ {input: $ i: 1} (нижний регистр) и, если это так, заменяет его на заданный символ $ {ucs: $ j: 1} (верхний регистр) и сохраняет его вернуться на вход.
input="${input/${input:$i:1}/${ucs:$j:1}}"
Это гораздо более быстрый вариант подхода JaredTS486, который использует собственные возможности Bash (включая версии Bash <4.0) для оптимизации его подхода.
Я рассчитал 1000 итераций этого подхода для маленькой строки (25 символов) и большей строки (445 символов) как для преобразования в нижний, так и в верхний регистр. Поскольку тестовые строки преимущественно строчные, преобразования в нижний регистр обычно выполняются быстрее, чем в верхний.
Я сравнил свой подход с несколькими другими ответами на этой странице, которые совместимы с Bash 3.2. Мой подход гораздо более эффективен, чем большинство описанных здесь подходов, и даже быстрее, чем tr
в нескольких случаях.
Вот временные результаты для 1000 итераций по 25 символов:
tr
строчных букв ; 3,81 с заглавными буквамиРезультаты синхронизации для 1000 итераций по 445 символов (состоящих из поэмы "Робин" Уиттера Биннера):
tr
строчных букв; 4с прописными буквамиРешение:
#!/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}"
}
Подход прост: хотя во входной строке есть все оставшиеся заглавные буквы, найдите следующую и замените все вхождения этой буквы ее строчным вариантом. Повторяйте, пока все заглавные буквы не будут заменены.
Некоторые характеристики производительности моего решения:
UCS
и LCS
может быть дополнен дополнительными символами