【发布时间】:2011-01-16 21:23:11
【问题描述】:
【问题讨论】:
标签: bash string bash shell lowercase
【问题讨论】:
标签: bash string bash shell lowercase
有多种方式:
$ 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。即使使用shopt -u nocasematch;,对我也不起作用(GNU bash 版本 4.2.46 和 4.0.33(以及相同的行为 2.05b.0,但没有实现 nocasematch))。取消设置 nocasematch 会导致 [[ "fooBaR" == "FOObar" ]] 匹配正常,但奇怪的是 [b-z] 与 [A-Z] 不正确匹配。 Bash 被双重否定(“unsetting nocasematch”)弄糊涂了! :-)
【讨论】:
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
切换(未记录,但可以在编译时配置)
$ 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。
【讨论】:
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:]'。它可能会出现同样的故障。所以问题至少部分不是 Bash 的。
echo "Hi All" | tr "[:upper:]" "[:lower:]"
【讨论】:
tr 不适用于非 ACII 字符。我确实生成了正确的语言环境集和语言环境文件。知道我做错了什么吗?
[:upper:]?
[:upper:]。
【讨论】:
a="$(tr [A-Z] [a-z] <<< "$a")" 对我来说看起来最简单。我还是个初学者……
sed解决方案;我一直在一个环境中工作,由于某种原因没有tr,但我还没有找到没有sed的系统,而且很多时候我想这样做我刚刚做了一些事情else in sed 无论如何都可以将这些命令链接到一个(长)语句中。
tr [A-Z] [a-z] A 中,如果存在由单个字母组成的文件名或设置了 nullgob,shell 可能会执行文件名扩展。 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=`node -p "\"$a\".toLowerCase()"`
你也可以使用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=`node -p "\"$a\".toUpperCase()"`
你也可以使用dd:
b=`echo "$a" | dd conv=ucase 2> /dev/null`
此外,当您说“shell”时,我假设您的意思是 bash,但如果您可以使用 zsh,那么就很简单了
b=$a:l
小写和
b=$a:u
为大写。
【讨论】:
a 的值包含一个单引号,那么您不仅有破坏行为,而且存在严重的安全问题。
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
【讨论】:
在 zsh 中:
echo $a:u
一定要喜欢 zsh!
【讨论】:
echo ${(C)a} #Upcase the first char only
使用 GNU sed:
sed 's/.*/\L&/'
例子:
$ foo="Some STRIng";
$ foo=$(echo "$foo" | sed 's/.*/\L&/')
$ echo "$foo"
some string
【讨论】:
预 Bash 4.0
Bash 降低字符串的大小写并赋值给变量
VARIABLE=$(echo "$VARIABLE" | tr '[:upper:]' '[:lower:]')
echo "$VARIABLE"
【讨论】:
echo 和管道:使用$(tr '[:upper:]' '[:lower:]' <<<"$VARIABLE")
你可以试试这个
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/
【讨论】:
对于仅使用内置函数的标准 shell(没有 bashism):
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。
在 bash 4 中你可以使用排版
例子:
A="HELLO WORLD"
typeset -l A=$A
【讨论】:
bash 的支持,它在 3.2.57(1) 中“卡住”了......(注意:是的,我知道我们总是可以从homebrew 安装更新的bash...)
简单的方法
echo "Hi all" | awk '{ print tolower($0); }'
【讨论】:
echo 'Đêm lưu trú năm nay' | awk '{ print tolower($0); }' => đêm lưu trú năm nay 和 echo 'ЛШТШФУМ АЩЬФ' | awk '{ print tolower($0); }' => лштшфум ащьф
我想感谢我希望分享的命令,但事实是我从http://commandlinefu.com 获得它供我自己使用。它的优点是,如果您 cd 到您自己的主文件夹中的任何目录,它将递归地将所有文件和文件夹更改为小写,请谨慎使用。这是一个出色的命令行修复程序,对您存储在驱动器上的大量专辑特别有用。
find . -depth -exec rename 's/(.*)\/([^\/]*)/$1\/\L$2/' {} \;
您可以指定一个目录来代替 find 后的点 (.),它表示当前目录或完整路径。
我希望这个解决方案证明是有用的,这个命令没有做的一件事是用下划线替换空格 - 哦,也许下次吧。
【讨论】:
prename from perl: dpkg -S "$(readlink -e /usr/bin/rename)" 给perl: /usr/bin/prename
仅对字母进行大小写转换。所以,这应该可以很好地工作。
我专注于将 a-z 之间的字母从大写转换为小写。任何其他字符都应该按原样打印在标准输出中......
将 a-z 范围内 path/to/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
【讨论】:
许多答案使用外部程序,实际上并没有使用Bash。
如果您知道您将使用 Bash4,那么您真的应该使用 ${VAR,,} 表示法(它既简单又酷)。对于 4 之前的 Bash(例如,我的 Mac 仍然使用 Bash 3.2)。我使用了@ghostdog74 答案的更正版本来创建更便携的版本。
您可以致电lowercase 'my STRING' 并获得小写版本。我阅读了有关将结果设置为 var 的 cmets,但这在 Bash 中并不是真正可移植的,因为我们无法返回字符串。打印它是最好的解决方案。使用var="$(lowercase $str)" 之类的东西很容易捕获。
这是如何工作的
其工作方式是使用printf 获取每个字符的ASCII 整数表示,然后使用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
这是带有示例的工作版本。
请注意代码中的 cmets,因为它们解释了很多东西:
#!/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 选项。
【讨论】:
如果使用 v4,则为 baked-in。如果没有,这里有一个简单、广泛适用的解决方案。此线程上的其他答案(和 cmets)对创建下面的代码很有帮助。
# 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} 允许它在字符串有引号的情况下工作。【讨论】:
这是JaredTS486's approach 的一个更快的变体,它使用原生 Bash 功能(包括 Bash
我已经为小字符串(25 个字符)和大字符串(445 个字符)计时了 1,000 次迭代,用于小写和大写转换。由于测试字符串主要是小写,因此转换为小写通常比转换为大写要快。
我已将我的方法与此页面上与 Bash 3.2 兼容的其他几个答案进行了比较。我的方法比这里记录的大多数方法性能要好得多,在某些情况下甚至比 tr 还要快。
以下是 25 个字符的 1000 次迭代的计时结果:
tr 转为小写;大写 3.81s445 个字符的 1000 次迭代的计时结果(由 Witter Bynner 的诗《罗宾》组成):
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 可以增加额外的字符【讨论】:
对于 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ÆØÅ
【讨论】:
echo "ABCÆØÅ" | ruby -pe '$_.downcase!' 工作正常吗?
对于 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 也有潜力,虽然它在 mee 中运行良好。
【讨论】:
不管这个问题有多老,并且类似于this answer by technosaurus。我很难找到一个可以跨大多数平台(我使用的)以及旧版本的 bash 移植的解决方案。我也对数组、函数以及使用打印、回声和临时文件来检索琐碎的变量感到沮丧。到目前为止,这对我来说非常有效,我想我会分享。 我的主要测试环境是:
- GNU bash,版本 4.1.2(1)-release (x86_64-redhat-linux-gnu)
- 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-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}}"
【讨论】:
将转换后的字符串存储到变量中。以下为我工作 -
$SOURCE_NAME 到 $TARGET_NAME
TARGET_NAME="`echo $SOURCE_NAME | tr '[:upper:]' '[:lower:]'`"
【讨论】:
来自bash 联机帮助页:
${参数^模式}
${参数^^模式}
${参数,模式}
${参数,,模式}
案例修改。此扩展修改了参数中字母字符的大小写。 模式被扩展以产生一个 模式就像在路径名扩展中一样。展开后的每个字符 parameter 的值根据 pattern 进行测试,如果匹配 模式,它的大小写被转换。该模式不应试图 匹配多个字符。 ^ 运算符转换小写 将 pattern 匹配为大写的字母; , 运算符转换 将大写字母与小写字母匹配。 ^^ 和 ,, 扩展转换扩展值中的每个匹配字符;这 ^ 和 , 扩展匹配并仅转换扩展值中的第一个字符。如果省略 pattern,则将其视为 ?,匹配每个字符。如果parameter为@或*,则依次对每个位置参数进行大小写修改操作,展开为结果列表。如果 参数是下标为@或*的数组变量,大小写修改操作应用于数组中的每个成员 转,展开就是结果列表。
【讨论】:
基于Dejay Clayton 优秀的解决方案,我将大写/小写泛化为转置函数(独立有用),将结果返回到变量中(更快/更安全),并添加了 BASH v4+ 优化:
pkg::transpose() { # <retvar> <string> <from> <to>
local __r=$2 __m __p
while [[ ${__r} =~ ([$3]) ]]; do
__m="${BASH_REMATCH[1]}"; __p="${3%${__m}*}"
__r="${__r//${__m}/${4:${#__p}:1}}"
done
printf -v "$1" "%s" "${__r}"
}
pkg::lowercase() { # <retvar> <string>
if (( BASH_VERSINFO[0] >= 4 )); then
printf -v "$1" "%s" "${2,,}"
else
pkg::transpose "$1" "$2" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
"abcdefghijklmnopqrstuvwxyz"
fi
}
pkg::uppercase() { # <retvar> <string>
if (( BASH_VERSINFO[0] >= 4 )); then
printf -v "$1" "%s" "${2^^}"
else
pkg::transpose "$1" "$2" "abcdefghijklmnopqrstuvwxyz" \
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
fi
}
为了简单起见,我没有添加任何 set -e 支持(或任何错误检查)...但除此之外它通常遵循 shellguide 和 pkg::transpose() 试图避免任何可能的变量名称冲突 @ 987654325@
【讨论】:
用这个命令做同样的事情,它会将大写字符串转换为小写:
sed 's/[A-Z]/[a-z]/g' <filename>
【讨论】:
[a-z]!