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

1766

中,有没有一种方法可以将字符串转换为小写字符串?

例如,如果我有:

a="Hi all"

我想将它转换为:

"hi all"

3
请参阅:https://dev59.com/XGgu5IYBdhLWcg3wWVyF - dreftymac
29个回答

2957
有多种方法:
POSIX标准
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

沙发

$ 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

注意:这个可能因人而异。对我来说不起作用(GNU bash版本4.2.46和4.0.33(以及相同行为的2.05b.0,但nocasematch未实现)),即使使用shopt -u nocasematch;也不行。取消设置nocasematch会导致[[ "fooBaR" == "FOObar" ]]匹配成功,但在case语句内部,奇怪的是[b-z][A-Z]错误地匹配。Bash被双重否定(“取消设置nocasematch”)所困惑! :-)

11
我可能漏掉了什么,或者你最后给出的Bash示例实际上做了完全不同的事情?它对于"ABX"有效,但如果你像其他示例一样改为word="Hi All",它会返回ha而不是hi all。它只适用于大写字母并跳过已经小写的字母。 - jangosteve
30
请注意,仅tr和awk示例在POSIX标准中得到了指定。 - Richard Hansen
204
tr '[:upper:]' '[:lower:]' 会使用当前语言环境来确定大写/小写的对应关系,因此它可以适用于使用带变音符号字母的语言环境。 - Richard Hansen
17
如何将输出存储到一个新变量中?比如说,我想要将小写字符串存储到一个新变量中? - Adam Parkin
83
这段代码的意思是将变量a中的大写字母转换成小写字母,并将结果存储在变量b中。具体实现是通过使用tr命令,将所有出现在[A-Z]字符集中的字符替换为对应的小写字母,然后将结果赋值给变量b - Tino
显示剩余24条评论

555
在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。

6
有点奇怪,"^^" 和 ",," 操作符不能用于非ASCII字符,但是 "" 可以... 所以 `string="łódź"; echo ${string} 返回 "ŁÓDŹ",但是echo ${string^^}返回 "łóDź"。即使在LC_ALL=pl_PL.utf-8` 的环境下也是如此。这是在使用 Bash 4.2.24 版本。 - Hubert Kario
2
@HubertKario:很奇怪。在Bash 4.0.33中,使用相同的字符串en_US.UTF-8,我也遇到了同样的问题。这是一个bug,我已经报告了。 - Dennis Williamson
1
@HubertKario: 尝试使用echo "$string" | tr '[:lower:]' '[:upper:]'。它可能会展示相同的失败。因此问题至少在某种程度上与Bash无关。 - Dennis Williamson
1
@DennisWilliamson: 是啊,我也注意到了(见对 Shuvalov 回答的评论)。我只会说,“这些东西仅适用于 ASCII”,但是它们的工作原理就是“~~”运算符,所以代码和转换表早已存在…… - Hubert Kario
4
Bash维护者已经承认了这个漏洞,并表示它将在下一个版本中得到修复。 - Dennis Williamson
显示剩余6条评论

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

5
@RichardHansen说:tr 对于非ASCII字符对我不起作用。 我已经设置了正确的区域设置并生成了区域设置文件。 你知道我可能做错了什么吗? - Hubert Kario
10
为什么需要使用[:upper:] - mgutt
1
同样的问题是为什么需要 [:upper:] - MaXi32
1
@mgutt和MaXi32:它指定将字符从大写转换为小写。 - Tim Skov Jacobsen
1
tr 需要两个参数 - from 字符列表和 to 字符列表。[:upper:] 是一个字符类,它只是一种花哨的方式来表示所有大写字母的列表(尽管有些问题是关于 tr 是否正确地考虑了 Unicode 而不仅仅是 ASCII)。然后,[:lower:] 是所有小写字母的列表。tr 然后取两个列表并将 from 列表中的字符转换为 to 列表中对应的字符。因此,需要 [:upper:] 以便 tr 知道它应该更改什么,而 [:lower:] 告诉它要更改成什么。 - Dan Hunsaker
显示剩余2条评论

113

tr

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

AWK

{ print tolower($0) }

sed

y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/

2
+1 a="$(tr [A-Z] [a-z] <<< "$a")" 对我来说看起来最简单。我还是个初学者... - Sandeepan Nath
2
我强烈推荐使用 sed 的解决方案; 我一直在一个没有 tr 的环境中工作,但我还没有遇到过没有 sed 的系统,而且许多时候,我想要做这件事情时已经用 sed 做了其他事情,因此可以将多个命令链接在一起成为一个(长)语句。 - Haravikk
2
括号表达式应该被引用。在 tr [A-Z] [a-z] A 中,如果存在由单个字母组成的文件名或设置了 nullglob,则 shell 可能会执行文件名扩展。tr "[A-Z]" "[a-z]" A 将会正常工作。 - Dennis
3
@CamiloMartin,我遇到了这个问题,在BusyBox系统中,特别是Synology NAS,但我也在其他几个系统上遇到了这个问题。最近我一直在进行跨平台的shell脚本编写,并且要求不安装任何额外的软件包,这使得事情变得非常棘手!然而,我还没有遇到过没有 sed 的系统。 - Haravikk
3
请注意,tr [A-Z] [a-z] 在几乎所有语言环境下都是不正确的。例如,在 en-US 语言环境中,A-Z 实际上是区间 AaBbCcDdEeFfGgHh...XxYyZ - fuz
显示剩余4条评论

98

我知道这是一个有些老旧的帖子,但我曾在另一个网站上回答了一个类似的问题,所以我想在这里发布它:

UPPER -> lower: 使用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=`node -p "\"$a\".toLowerCase()"`

您也可以使用 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($1) }'`

或 Sed:
b=`echo "$a" | sed 's/./\U&/g'`

或者 Bash 4:

b=${a^^}

或者 NodeJS:

b=`node -p "\"$a\".toUpperCase()"`

您还可以使用dd

b=`echo "$a" | dd  conv=ucase 2> /dev/null`

当您说“shell”时,我假设您指的是bash,但如果您可以使用zsh,那么这很容易实现:

b=$a:l

对于小写字母和

b=$a:u

转换成大写字母。


@JESii 都对我有效,无论是大写转小写还是小写转大写。我正在使用64位Debian Stretch上的sed 4.2.2和Bash 4.3.42(1)。 - nettux
1
嗨,@nettux443...我刚刚再次尝试了bash操作,但仍然失败,并显示错误消息“bad substitution”。我正在使用homebrew的bash:GNU bash,版本4.3.42(1)-release(x86_64-apple-darwin14.5.0),我的操作系统是OSX。 - JESii
10
请勿使用!生成脚本的所有示例都非常脆弱;如果 a 的值包含单引号,则不仅会破坏行为,而且还会造成严重的安全问题。 - tripleee
我最喜欢的是sed解决方案,因为sed无处不在。 - Dudi Boy
我在zsh中尝试了sed 's/./\L&/g',但输出结果全是L... - Walter Tross
显示剩余2条评论

85

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

1
绝对值得比目前更多的点赞! - Umlin
1
@Umlin 这是一个全新的功能,因此还没有得到太多关注是很正常的。 - fedorqui
1
我现在还不能使用它,但很高兴知道这是一件事情! - Lee Harrison
8
еУ¶пЉМе•ЗжА™гАВжИСжГ≥зЯ•йБУдЄЇдїАдєИдїЦдїђи¶БеЉХеЕ•ињЩдЄ™пЉМељУ${v^^}еТМ${v,,}еЈ≤зїПе≠ШеЬ®гАВ - Gostega

35
在zsh中:
echo $a:u

真心喜欢zsh!


5
将 $a 转换为小写字母,记作 $l。 - Scott Smedley
2
增加一个案例:echo ${(C)a} #仅将第一个字符大写 - biocyberman
@biocyberman 有没有一种方法只将第一个字符转换为小写? - karlahrnndz
1
这不是我所知道的。您可以在此处阅读有关可用标志的信息:https://zsh.sourceforge.io/Doc/Release/Expansion.html#Parameter-Expansion-Flags - biocyberman
1
@karlahrnndz 实际上你可以这样做:${a:0:1:l}${a:1},只将第一个字符转换为小写。 - biocyberman

20

使用 GNU sed

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

例子:

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

18

在Bash 4.0之前

Bash将字符串转换为小写并赋值给变量

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

echo "$VARIABLE"

7
无需使用 echo 和管道:使用 $(tr '[:upper:]' '[:lower:]' <<<"$VARIABLE") 将变量转换为小写。 - Tino
3
@Tino,here字符串在非常老的Bash版本中也不可移植;我相信它是在v3中引入的。 - tripleee
1
@tripleee 你说得对,它是在bash-2.05b中引入的 - 然而这是我在我的系统上能找到的最旧的bash版本。 - Tino

14

对于 Bash 命令行,根据语言环境和国际字母,这可能有效(结合他人的回答):

$ echo "ABCÆØÅ" | python -c "print(open(0).read().lower())"
abcæøå
$ echo "ABCÆØÅ" | sed 's/./\L&/g'
abcæøå
$ export a="ABCÆØÅ" | echo "${a,,}"
abcæøå

这些变化可能是无效的:

$ echo "ABCÆØÅ" | tr "[:upper:]" "[:lower:]"
abcÆØÅ
$ echo "ABCÆØÅ" | awk '{print tolower($1)}'
abcÆØÅ
$ echo "ABCÆØÅ" | perl -ne 'print lc'
abcÆØÅ
$ echo 'ABCÆØÅ' | dd conv=lcase 2> /dev/null
abcÆØÅ

2
echo "ABCÆØÅ" | ruby -pe '$_.downcase!' 正常工作吗? - Fravadona
是的。Ruby版本也可以在我的设置中运行。 - Finn Årup Nielsen
可能不是BSD的sed。 - Nakilon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接