【问题标题】:How to convert a string to lower case in Bash?如何在 Bash 中将字符串转换为小写?
【发布时间】:2011-01-16 21:23:11
【问题描述】:

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

例如,如果我有:

a="Hi all"

我想把它转换成:

"hi all"

【问题讨论】:

标签: bash string bash shell lowercase


【解决方案1】:

有多种方式:

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。即使使用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”)弄糊涂了! :-)

【讨论】:

  • 我是否遗漏了什么,或者您的最后一个示例(在 Bash 中)实际上做了一些完全不同的事情?它适用于“ABX”,但如果您像其他示例一样创建word="Hi All",它将返回ha,而不是hi all。它仅适用于大写字母并跳过已经小写的字母。
  • 请注意,POSIX 标准中仅指定了trawk 示例。
  • tr '[:upper:]' '[:lower:]' 将使用当前语言环境来确定大写/小写等值,因此它适用于使用带有变音符号的字母的语言环境。
  • 如何将输出转换为新变量?即说我想把小写的字符串变成一个新的变量?
  • @Adam: b="$(echo $a | tr '[A-Z]' '[a-z]')"
【解决方案2】:

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

【讨论】:

  • 很奇怪,“^^”和“,”运算符不适用于非 ASCII 字符,但“~~”可以...所以string="łódź"; echo ${string~~} 将返回“ŁÓDŹ”,但是echo ${string^^} 返回“łóDź”。即使在LC_ALL=pl_PL.utf-8。那是使用 bash 4.2.24。
  • @HubertKario:这很奇怪。在 Bash 4.0.33 中,en_US.UTF-8 中的字符串相同,这对我来说是一样的。这是一个错误,我已经报告了。
  • @HubertKario:试试echo "$string" | tr '[:lower:]' '[:upper:]'。它可能会出现同样的故障。所以问题至少部分不是 Bash 的。
  • @DennisWilliamson:是的,我也注意到了(请参阅对 Shuvalov 回答的评论)。我只想说,“这东西只适用于 ASCII”,但它是“~~” 操作符确实有效,所以它不像代码和翻译表已经不存在......
  • @HubertKario:Bash 维护者有acknowledged 的错误,并表示将在下一个版本中修复。
【解决方案3】:
echo "Hi All" | tr "[:upper:]" "[:lower:]"

【讨论】:

  • @RichardHansen: tr 不适用于非 ACII 字符。我确实生成了正确的语言环境集和语言环境文件。知道我做错了什么吗?
  • 仅供参考:这适用于 Windows/Msys。其他一些建议没有。
  • 为什么需要[:upper:]
  • 同样的问题为什么需要[:upper:]
  • @mgutt 和 MaXi32:指定从上到下翻译字符。
【解决方案4】:

tr:

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

AWK:

{ print tolower($0) }

sed:

y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/

【讨论】:

  • +1 a="$(tr [A-Z] [a-z] &lt;&lt;&lt; "$a")" 对我来说看起来最简单。我还是个初学者……
  • 我强烈推荐sed解决方案;我一直在一个环境中工作,由于某种原因没有tr,但我还没有找到没有sed的系统,而且很多时候我想这样做我刚刚做了一些事情else in sed 无论如何都可以将这些命令链接到一个(长)语句中。
  • 括号表达式应该被引用。在tr [A-Z] [a-z] A 中,如果存在由单个字母组成的文件名或设置了 nullgob,shell 可能会执行文件名扩展。 tr "[A-Z]" "[a-z]" A 会正常运行。
  • @CamiloMartin 这是一个 BusyBox 系统,我遇到了这个问题,特别是 Synology NASes,但我在其他一些系统上也遇到过。我最近一直在做很多跨平台的 shell 脚本,并且要求不安装任何额外的东西,这让事情变得非常棘手!但是我还没有遇到没有sed的系统
  • 请注意,tr [A-Z] [a-z] 在几乎所有语言环境中都不正确。例如,在en-US 语言环境中,A-Z 实际上是区间AaBbCcDdEeFfGgHh...XxYyZ
【解决方案5】:

我知道这是一篇过时的帖子,但我为另一个网站做了这个答案,所以我想我会把它贴在这里:

上 -> 下: 使用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

为大写。

【讨论】:

  • @JESii 都适用于我的上 -> 下和下 -> 上。我在 64 位 Debian Stretch 上使用 sed 4.2.2 和 Bash 4.3.42(1)。
  • 嗨,@nettux443... 我刚刚再次尝试了 bash 操作,但它仍然失败,并显示错误消息“替换错误”。我在 OSX 上使用自制的 bash:GNU bash,版本 4.3.42(1)-release (x86_64-apple-darwin14.5.0)
  • 不要使用! 所有生成脚本的例子都非常脆弱;如果a 的值包含一个单引号,那么您不仅有破坏行为,而且存在严重的安全问题。
  • 我最喜欢 sed 解决方案,因为 sed 总是无处不在。
  • 我更喜欢使用 dd 解决方案。请注意,您需要 root 才能使其正常工作
【解决方案6】:

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

【讨论】:

  • 绝对值得获得比目前更多的支持!
  • @Umlin 是一个全新的功能,所以没有引起太多关注是正常的。
  • 我还不能用这个,但很高兴知道它是一个东西!
  • @LeeHarrison 你可以很容易地安装它,我推荐给你:)
【解决方案7】:

在 zsh 中:

echo $a:u

一定要喜欢 zsh!

【讨论】:

  • 或 $a:l 用于小写转换
  • 再添加一个案例:echo ${(C)a} #Upcase the first char only
【解决方案8】:

使用 GNU sed:

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

例子:

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

【讨论】:

    【解决方案9】:

    预 Bash 4.0

    Bash 降低字符串的大小写并赋值给变量

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

    【讨论】:

    • 不需要echo 和管道:使用$(tr '[:upper:]' '[:lower:]' &lt;&lt;&lt;"$VARIABLE")
    • @Tino 这里的字符串也不能移植回真正旧版本的 Bash;我相信它是在 v3 中引入的。
    • @tripleee 你说得对,它是在 bash-2.05b 中引入的——但这是我能在我的系统上找到的最古老的 bash
    【解决方案10】:

    你可以试试这个

    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/

    【讨论】:

    • 太棒了!正要做出这样的回答。许多答案添加了大量不需要的信息
    【解决方案11】:

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

    【讨论】:

    • 我想知道你是否没有在这个脚本中加入一些 bashism,因为它在 FreeBSD 上不可移植 sh: ${1:$...}: Bad replacement
    • 确实;带有${var:1:1} 的子字符串是 Bashism。
    • 这种方法的性能指标很差。请参阅我对指标的回答。
    【解决方案12】:

    在 bash 4 中你可以使用排版

    例子:

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

    【讨论】:

    • 啊,我们可怜的 macOS 用户,现在是 2020 年,Apple 已经放弃了对 bash 的支持,它在 3.2.57(1) 中“卡住”了......(注意:是的,我知道我们总是可以从homebrew 安装更新的bash...)
    【解决方案13】:

    简单的方法

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

    【讨论】:

    • 最好使用能正确处理 UTF8 编码字符(以及不同语言字符集)的 gawk。 'Awk tolower' 将在“ЛШТШФУМ АЩЬФ”之类的内容上失败。
    • macOS 11.6 上可用的 awk 完美运行:echo 'Đêm lưu trú năm nay' | awk '{ print tolower($0); }' => đêm lưu trú năm nayecho 'ЛШТШФУМ АЩЬФ' | awk '{ print tolower($0); }' => лштшфум ащьф
    【解决方案14】:

    正则表达式

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

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

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

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

    【讨论】:

    • 无论出于何种原因,这对我都不起作用,尽管它看起来不错。我确实得到了这个作为替代方案:find . -exec /bin/bash -c 'mv {} `tr [A-Z] [a-z]
    • 这需要prename from perl: dpkg -S "$(readlink -e /usr/bin/rename)"perl: /usr/bin/prename
    【解决方案15】:

    仅对字母进行大小写转换。所以,这应该可以很好地工作。

    我专注于将 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
    

    【讨论】:

      【解决方案16】:

      许多答案使用外部程序,实际上并没有使用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-&gt;lower,或者subtracting 32 如果lower-to-&gt;upper。然后再次使用printf 将数字转换回字符。从'A' -to-&gt; '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 选项。

      【讨论】:

        【解决方案17】:

        如果使用 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" )
        • 在 lcase 函数中,使用 ${!1//\'/"'\''"} 而不是 ${!1} 允许它在字符串有引号的情况下工作。

        【讨论】:

          【解决方案18】:

          这是JaredTS486's approach 的一个更快的变体,它使用原生 Bash 功能(包括 Bash

          我已经为小字符串(25 个字符)和大字符串(445 个字符)计时了 1,000 次迭代,用于小写和大写转换。由于测试字符串主要是小写,因此转换为小写通常比转换为大写要快。

          我已将我的方法与此页面上与 Bash 3.2 兼容的其他几个答案进行了比较。我的方法比这里记录的大多数方法性能要好得多,在某些情况下甚至比 tr 还要快。

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

          445 个字符的 1000 次迭代的计时结果(由 Witter Bynner 的诗《罗宾》组成):

          • 2s 用于我的小写方法; 12s 表示大写
          • 4s 将tr 转为小写; 4s 表示大写
          • 20s 将Orwellophile's approach 转为小写; 29s 表示大写
          • 75s for ghostdog74's 小写; 669s 为大写。有趣的是,主要匹配的测试与主要未命中的测试之间的性能差异有多么显着
          • 467s 将technosaurus' approach 转为小写; 449 表示大写
          • 660s for JaredTS486's approach 转小写; 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. 避免使用会导致性能损失的子 shell
          3. 使用针对性能进行编译和优化的 shell 机制,例如变量内的全局字符串替换、变量后缀修剪以及正则表达式搜索和匹配。这些机制比手动遍历字符串要快得多
          4. 仅循环要转换的唯一匹配字符的计数所需的次数。例如,将具有三个不同大写字符的字符串转换为小写只需要 3 次循环迭代。对于预配置的 ASCII 字母表,循环迭代的最大次数为 26
          5. UCSLCS 可以增加额外的字符

          【讨论】:

            【解决方案19】:

            对于 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!' 工作正常吗?
            • 是的。 Ruby 版本也适用于我的设置。
            【解决方案20】:

            对于 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 中运行良好。

            【讨论】:

            • 不错!有关此方法的性能分析,请参阅我对指标的回答。
            【解决方案21】:

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

            1. GNU bash,版本 4.1.2(1)-release (x86_64-redhat-linux-gnu)
            2. 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}}"
            

            【讨论】:

            • 这非常低效,在上面的示例中循环了 650 次,在我的机器上执行 1000 次调用需要 35 秒。对于仅循环 11 次且执行 1000 次调用所需时间不到 5 秒的替代方案,请参阅我的替代答案。
            • 谢谢,尽管这应该是显而易见的。也许页面错误来自输入大小和您正在执行的迭代次数。不过我喜欢你的解决方案。
            【解决方案22】:

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

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

            【讨论】:

              【解决方案23】:

              来自bash 联机帮助页:

              ${参数^模式}

              ${参数^^模式}

              ${参数,模式}

              ${参数,,模式}

              案例修改。此扩展修改了参数中字母字符的大小写。 模式被扩展以产生一个 模式就像在路径名扩展中一样。展开后的每个字符 parameter 的值根据 pattern 进行测试,如果匹配 模式,它的大小写被转换。该模式不应试图 匹配多个字符。 ^ 运算符转换小写 将 pattern 匹配为大写的字母; , 运算符转换 将大写字母与小写字母匹配。 ^^,, 扩展转换扩展值中的每个匹配字符;这 ^, 扩展匹配并仅转换扩展值中的第一个字符。如果省略 pattern,则将其视为 ?,匹配每个字符。如果parameter@*,则依次对每个位置参数进行大小写修改操作,展开为结果列表。如果 参数是下标为@*的数组变量,大小写修改操作应用于数组中的每个成员 转,展开就是结果列表。

              【讨论】:

                【解决方案24】:

                基于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 支持(或任何错误检查)...但除此之外它通常遵循 shellguidepkg::transpose() 试图避免任何可能的变量名称冲突 @ 987654325@

                【讨论】:

                  【解决方案25】:

                  用这个命令做同样的事情,它会将大写字符串转换为小写:

                  sed 's/[A-Z]/[a-z]/g' <filename>
                  

                  【讨论】:

                  • 那根本行不通。它将每个大写字母替换为 5 个字符的字符串 [a-z]!
                  猜你喜欢
                  • 2012-07-08
                  • 2021-06-11
                  • 1970-01-01
                  • 1970-01-01
                  • 2014-06-05
                  • 1970-01-01
                  • 1970-01-01
                  • 2010-11-04
                  • 2010-12-29
                  相关资源
                  最近更新 更多