首页 文章

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

提问于
浏览
978

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

例如,如果我有:

a="Hi all"

我想将其转换为:

"hi all"

19 回答

  • 10

    各种方式:

    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
    

    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
    
  • 3

    在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
    

    Headers 案例:

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

    Edit:

    按照 ghostdog74 的建议添加"toggle first character by word"( ${var~} ) .

    Edit: 更正了波形符合行为以匹配Bash 4.3 .

  • 3
    echo "Hi All" | tr "[:upper:]" "[:lower:]"
    
  • 113

    tr:

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

    AWK:

    { print tolower($0) }
    

    sed:

    y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
    
  • 0

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

    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=`echo "console.log('$a'.toLowerCase());" | node`
    

    你也可以使用 dd (但我不会!):

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

    lower -> 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`
    

    另外当你说'shell'我假设你的意思 bash 但如果你可以使用 zsh 它就像

    b=$a:l
    

    小写和

    b=$a:u
    

    对于大写 .

  • 6

    在zsh中:

    echo $a:u
    

    得爱zsh!

  • 3

    使用GNU sed

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

    例:

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

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

    Pre Bash 4.0

    Bash Lower the Case of a string and assign to variable

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

    正则表达式

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

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

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

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

  • 7

    在bash 4中,您可以使用排版

    例:

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

    你可以试试这个

    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/

  • 3

    如果使用v4,则为baked-in . 如果没有,这是一个 simple, widely applicable 解决方案 . 此线程上的其他答案(和注释)在创建下面的代码时非常有用 .

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

  • 36

    对于早于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也有潜力,虽然它确实适合我 .

  • 0

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

    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}}"
    
  • 71

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

    如果你知道你有Bash4可用,你应该只使用 ${VAR,,} 表示法(这很简单,很酷) . 对于4之前的Bash(我的Mac仍然使用Bash 3.2例如) . 我使用了@ ghostdog74的修正版本的答案来创建一个更便携的版本 .

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

    How this works

    这种方法的工作方式是使用 printf 获取每个字符的ASCII整数表示,然后如果 upper-to->lower 则获取 adding 32 ,或者 lower-to->upper 如果 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!
    

    This should only work for ASCII characters though .

    对我来说这很好,因为我知道我只会传递ASCII字符 .
    例如,我将此用于一些不区分大小写的CLI选项 .

  • 11

    转换大小写仅适用于字母 . 所以,这应该工作得很好 .

    我专注于将a-z之间的字母表从大写转换为小写 . 任何其他字符应该只在stdout中打印,因为它是......

    将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
    
  • 17

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

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

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

    我为这个小方法(25个字符)和一个更大的字符串(445个字符)计算了1000次迭代次数,用于小写和大写转换 . 由于测试字符串主要是小写字母,因此转换为小写字母通常比大写字母快 .

    我已将此方法与此页面上与Bash 3.2兼容的其他几个答案进行了比较 . 我的方法比这里记录的大多数方法更有效,并且在某些情况下甚至比_569125更快 .

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

    定时结果为445个字符的1000次迭代(由Witter Bynner的诗“The Robin”组成):

    • 2s我的小写方法; 12s为大写

    • 4s为 tr 为小写; 4s为大写

    • 20s Orwellophile's approach为小写; 29s表示大写

    • 75s for ghostdog74's接近小写; 669s为大写 . 值得注意的是,在具有主要匹配的测试与具有主要未命中的测试之间,性能差异是多么显着

    • 467s technosaurus' approach为小写;大写449s

    • 660s为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}"
    }
    

    方法很简单:输入字符串中存在任何剩余的大写字母,找到下一个字母,并用该小写字母替换该字母的所有实例 . 重复直到更换所有大写字母 .

    我的解决方案的一些性能特征:

    • 仅使用shell内置实用程序,这可以避免在新进程中调用外部二进制实用程序的开销

    • 避免子壳,这会导致性能损失

    • 使用针对性能进行编译和优化的shell机制,例如变量中的全局字符串替换,变量后缀修剪以及正则表达式搜索和匹配 . 这些机制比通过字符串手动迭代要快得多

    • 仅循环要转换的唯一匹配字符数所需的次数 . 例如,将具有三个不同大写字符的字符串转换为小写只需要3次循环迭代 . 对于预配置的ASCII字母表,循环迭代的最大数量为26

    • UCSLCS 可以使用其他字符进行扩充

相关问题