Відповіді:
Існують різні способи:
$ 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]. Баш плутає подвійний негатив ("невстановлювальний нокашмат")! :-)
word="Hi All"
як інші приклади, він повертається ha
, ні hi all
. Він працює лише для великих літер та пропускає літери, які вже є малими літерами.
tr
та awk
приклади.
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
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.
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
оболонці оболонка може виконувати розширення імені файлів, якщо є імена файлів, що складаються з однієї літери або встановлено nullgob . tr "[A-Z]" "[a-z]" A
буде вести себе належним чином.
sed
tr [A-Z] [a-z]
це невірно майже у всіх локалях. наприклад, у en-US
локалі - A-Z
це фактично інтервал AaBbCcDdEeFfGgHh...XxYyZ
.
Я знаю, що це стародавній пост, але я відповів на інший сайт, тому подумав, що опублікую його тут:
Вгору -> нижче : використовувати 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
для верхнього регістру.
a
містить одну цитату, у вас є не тільки порушена поведінка, але й серйозна проблема безпеки.
В zsh:
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}
- це башизм.
Ви можете спробувати це
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/
Я хотів би взяти подяку за команду, яку хочу поділитися, але правда, я отримав її для власного використання від 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 (наприклад, у 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.
Перетворення корпусу робиться лише для алфавітів. Отже, це повинно працювати акуратно.
Я зосереджуюсь на перетворенні алфавітів між 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
Якщо використовується 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, ця версія повинна бути найшвидшою (оскільки вона не розщеплює / не виконує жодних команд):
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"
}
Відповідь технозавра теж мав потенціал, хоча він працював належним чином для мене.
Незважаючи на те, скільки років це питання, і подібний на цю відповідь технозавр . Мені важко було знайти рішення, яке було портативним на більшості платформ (That I Use), а також у старих версіях 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 для циклу, який можна повторити через рядки. Для рядка нижче, якщо ви ще нічого подібного не бачили, саме тут я дізнався це . У цьому випадку рядок перевіряє, чи існує char $ {input: $ i: 1} (нижній регістр), і якщо так, замінює його на даний char $ {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,81s для великих літерРезультати часу для 1000 ітерацій 445 символів (що складаються з поеми Віттера Байннера "Робін"):
tr
малих літер; 4s для великих літерРішення:
#!/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
можна доповнити додатковими символами