如何在Bash中将字符串转换为小写?

时间:2010-02-15 07:02:57

标签: string bash shell uppercase lowercase

中是否有办法将字符串转换为小写字符串?

例如,如果我有:

a="Hi all"

我想将其转换为:

"hi all"

22 个答案:

答案 0 :(得分:1857)

有多种方式:

POSIX standard

tr

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

AWK

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

非POSIX

使用以下示例可能会遇到可移植性问题:

Bash 4.0

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

sed

$ 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

Bash

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”]]匹配OK BUT内部奇怪地[b-z]被[A-Z]错误地匹配。 Bash被双阴性(“未设置的nocasematch”)弄糊涂了! : - )

答案 1 :(得分:393)

在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选项更改变量的属性,但不更改内容。我的示例中的重新分配更新了内容以显示更改。

修改

ghostdog74 的建议添加“按字首字母切换”(${var~})。

编辑:更正了波形符合行为以匹配Bash 4.3。

答案 2 :(得分:117)

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

答案 3 :(得分:74)

tr

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

AWK

{ print tolower($0) }

sed

y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/

答案 4 :(得分:41)

我知道这是一个古老的帖子,但我为另一个网站做了这个答案,所以我想我会把它发布在这里:

UPPER - &gt;下: 使用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($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`

更低 - &gt; UPPER

使用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($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

表示大写。

答案 5 :(得分:28)

在zsh中:

echo $a:u

得爱zsh!

答案 6 :(得分:17)

使用GNU sed

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

示例:

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

答案 7 :(得分:11)

Pre Bash 4.0

Bash降低字符串的大小写并分配给变量

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

echo "$VARIABLE"

答案 8 :(得分:11)

对于仅使用内置函数的标准shell(没有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}"
}

答案 9 :(得分:8)

在bash 4中你可以使用排版

示例:

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

答案 10 :(得分:7)

正则表达式

我想赞扬我希望分享的命令,但事实是我从http://commandlinefu.com获得了我自己使用的命令。它的优点是,如果您cd到您自己的主文件夹中的任何目录,它将以递归方式将所有文件和文件夹更改为小写,请谨慎使用。这是一个出色的命令行修复,对于存储在驱动器上的大量专辑特别有用。

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

您可以在find之后指定一个目录来代替点(。),表示当前目录或完整路径。

我希望这个解决方案证明有用,这个命令没有做的一件事是用下划线替换空格 - 哦,也许是另一个时间。

答案 11 :(得分:7)

你可以试试这个

s="Hello World!" 

echo $s  # Hello World!

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

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

enter image description here

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

答案 12 :(得分:3)

如果使用v4,则为baked-in。如果没有,这是一个简单,广泛适用的解决方案。这个帖子的其他答案(和评论)在创建下面的代码时非常有帮助。

# 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}也可以使用它。

答案 13 :(得分:3)

对于早于4.0的Bash版本,此版本应该是最快的(因为它没有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"
}

technosaurus's answer也有潜力,虽然它确实适合我。

答案 14 :(得分:3)

尽管这个问题多久了,但与this answer by technosaurus类似。我很难找到一个可以在大多数平台(我使用的)以及旧版本的bash上移植的解决方案。我也对数组,函数以及打印,回声和临时文件的使用感到沮丧,以检索琐碎的变量。到目前为止,这对我来说非常有效,我想我会分享。 我的主要测试环境是:

  
      
  1. GNU bash,版本4.1.2(1)-release(x86_64-redhat-linux-gnu)
  2.   
  3. GNU bash,版本3.2.57(1)-release(sparc-sun-solaris2.10)
  4.   
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-style for loop来遍历字符串。 对于下面的行,如果你之前没有见过这样的话 this is where I learned this。在这种情况下,行检查输入中是否存在char $ {input:$ i:1}(小写),如果是,则用给定的char $ {ucs:$ j:1}(大写)替换它并存储它回到输入。

input="${input/${input:$i:1}/${ucs:$j:1}}"

答案 15 :(得分:3)

使用外部程序的许多答案,实际上并没有使用Bash

如果您知道Bash4可用,那么您应该使用${VAR,,}符号(这很简单,很酷)。对于4之前的Bash(我的Mac仍然使用Bash 3.2)。我使用@ ghostdog74的修正版本的答案来创建一个更便携的版本。

您可以拨打lowercase 'my STRING'并获得小写版本。我读到了关于将结果设置为var的注释,但在Bash中这并不是真正可移植的,因为我们无法返回字符串。打印它是最好的解决方案。使用var="$(lowercase $str)"等内容轻松捕捉。

如何运作

这种方法的工作方式是使用printf获取每个字符的ASCII整数表示,然后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 "$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选项,例如。

答案 16 :(得分:2)

转换案例仅适用于字母。所以,这应该工作得很好。

我专注于将a-z之间的字母表从大写字母转换为小写字母。任何其他字符都应该在stdout中打印出来......

将a-z范围内的路径/中的所有文本转换为/ file / filename到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

答案 17 :(得分:2)

如果您喜欢python并可以选择安装新的python软件包,则可以尝试使用此python utility

# install pythonp
$ pip install pythonp

$ echo $a | pythonp "l.lower()"

答案 18 :(得分:1)

这是JaredTS486's approach的更快变体,它使用本机Bash功能(包括Bash版本<4.0)来优化他的方法。

我已经为小字符串(25个字符)和大字符串(445个字符)定时了1000次此方法的迭代,无论是小写还是大写转换。由于测试字符串主要是小写字母,因此转换为小写字母通常比转换为大写字母更快。

我已将我的方法与本页上其他与Bash 3.2兼容的答案进行了比较。我的方法比此处记录的大多数方法具有更高的性能,在某些情况下甚至比tr更快。

以下是25个字符的1,000次迭代的计时结果:

1,000次迭代的445个字符的计时结果(由Witter Bynner的诗歌“ The Robin”组成):

    我使用小写字母的时间为
  • 2s;大写字母为12秒
  • tr
  • 4s小写;大写字母为4s
  • {li>
  • 20秒使Orwellophile's approach小写;大写字母为29s
  • 对于ghostdog74's
  • 75秒为小写;大写为669s。有趣的是,在比赛占优势的测试与失误占优势的测试之间,性能差异有多么大。
  • technosaurus' approach为小写的
  • 467秒;大写字母449s
  • JaredTS486's approach为小写的
  • 660s;大写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内置实用程序,从而避免了在新进程中调用外部二进制实用程序的开销。
  2. 避免使用子外壳,这会导致性能损失
  3. 使用经过编译和优化以提高性能的Shell机制,例如变量内的全局字符串替换,变量后缀修整以及正则表达式搜索和匹配。这些机制比通过字符串手动迭代要快得多
  4. 仅循环计数要转换的唯一匹配字符所需的次数。例如,将具有三个不同大写字符的字符串转换为小写仅需要3次循环迭代。对于预配置的ASCII字母,最大循环迭代次数为26
  5. UCSLCS可以增加其他字符

答案 19 :(得分:0)

将转换后的字符串存储到变量中。以下为我工作 - $SOURCE_NAME$TARGET_NAME

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

答案 20 :(得分:0)

简单方法

echo "Hi all" | awk '{ print tolower($0); }'

答案 21 :(得分:0)

Bash 5.1通过L参数转换提供了一种直接的方法:

${var@L}

例如,您可以说:

$ v="heLLo"
$ echo "${v@L}"
hello

您还可以对U进行大写:

$ v="hello"
$ echo "${v@U}"
HELLO

u的第一个字母大写:

$ v="hello"
$ echo "${v@u}"
Hello