Как преобразовать строку в нижний регистр в 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
выключить
я знаю, что это старомодный пост, но я сделал этот ответ для другого сайта, поэтому я подумал, что опубликую его здесь:
верхний -> нижний: использовать 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
в верхнем регистре.
использование 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/' {} \;
вы можете указать каталог вместо точки(.) после поиска, который обозначает текущий каталог или полный путь.
Я надеюсь, что это решение окажется полезным одна вещь, эта команда не заменить пробелы символом подчеркивания - ну возможно в другой раз.
вы можете попробовать это
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 ""=\'$(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. Я также был разочарован массивами, функциями и использованием отпечатков, эхо и временных файлов для извлечения тривиальных переменных. Это работает очень хорошо для меня, пока я думал, что поделюсь. Мои основные среды тестирования:
- GNU bash, начиная с версии 4.1.2(1)-релиз (архитектуру x86_64-RedHat это-линукс-гну)
- 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}"
}
подход прост: в то время как входная строка имеет любые оставшиеся прописные буквы, найдите следующую, и замените все экземпляры этой буквы ее строчным вариантом. Повторяйте до тех пор, пока не будут заменены все заглавные буквы.
некоторые характеристики моего решения:
- использует только утилиты Shell builtin, что позволяет избежать накладных расходов на вызов внешних двоичных утилит в новом процессе
- избегает суб-оболочек, которые несут штрафы за производительность
- использует механизмы оболочки, которые скомпилированы и оптимизированы для производительности, такие как глобальная замена строк в переменных, обрезка суффиксов переменных и поиск и сопоставление регулярных выражений. Эти механизмы намного быстрее, чем итерация вручную через строки
- циклы только количество раз, требуемое количеством уникальных совпадающих символов для преобразования. Например, преобразование строки с тремя разными символами верхнего регистра в нижний регистр требует только 3 итераций цикла. Для предварительно настроенного алфавита ASCII максимальное число итераций цикла это 26
-
UCS
иLCS
можно дополнить дополнительными символами