How to convert a string to lower case in Bash?

前端 未结 20 2019
慢半拍i
慢半拍i 2020-11-22 09:40

Is there a way in bash to convert a string into a lower case string?

For example, if I have:

a=\"Hi all\"

I want to convert it to:<

相关标签:
20条回答
  • 2020-11-22 10:07
    echo "Hi All" | tr "[:upper:]" "[:lower:]"
    
    0 讨论(0)
  • 2020-11-22 10:07

    Many answers using external programs, which is not really using Bash.

    If you know you will have Bash4 available you should really just use the ${VAR,,} notation (it is easy and cool). For Bash before 4 (My Mac still uses Bash 3.2 for example). I used the corrected version of @ghostdog74 's answer to create a more portable version.

    One you can call lowercase 'my STRING' and get a lowercase version. I read comments about setting the result to a var, but that is not really portable in Bash, since we can't return strings. Printing it is the best solution. Easy to capture with something like var="$(lowercase $str)".

    How this works

    The way this works is by getting the ASCII integer representation of each char with printf and then adding 32 if upper-to->lower, or subtracting 32 if lower-to->upper. Then use printf again to convert the number back to a char. From 'A' -to-> 'a' we have a difference of 32 chars.

    Using printf to explain:

    $ printf "%d\n" "'a"
    97
    $ printf "%d\n" "'A"
    65
    

    97 - 65 = 32

    And this is the working version with examples.
    Please note the comments in the code, as they explain a lot of stuff:

    #!/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
    

    And the results after running this:

    $ ./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.

    For me it is fine, since I know I will only pass ASCII chars to it.
    I am using this for some case-insensitive CLI options, for example.

    0 讨论(0)
  • 2020-11-22 10:07

    For Bash versions earlier than 4.0, this version should be fastest (as it doesn't fork/exec any commands):

    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 had potential too, although it did run properly for mee.

    0 讨论(0)
  • 2020-11-22 10:10

    In Bash 4:

    To lowercase

    $ 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
    

    To uppercase

    $ 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
    

    Toggle (undocumented, but optionally configurable at compile time)

    $ 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
    

    Capitalize (undocumented, but optionally configurable at compile time)

    $ string="a few words"
    $ declare -c string
    $ string=$string
    $ echo "$string"
    A few words
    

    Title case:

    $ 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
    

    To turn off a declare attribute, use +. For example, declare +c string. This affects subsequent assignments and not the current value.

    The declare options change the attribute of the variable, but not the contents. The reassignments in my examples update the contents to show the changes.

    Edit:

    Added "toggle first character by word" (${var~}) as suggested by ghostdog74.

    Edit: Corrected tilde behavior to match Bash 4.3.

    0 讨论(0)
  • 2020-11-22 10:15

    tr:

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

    AWK:

    { print tolower($0) }
    

    sed:

    y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
    
    0 讨论(0)
  • 2020-11-22 10:15

    Regular expression

    I would like to take credit for the command I wish to share but the truth is I obtained it for my own use from http://commandlinefu.com. It has the advantage that if you cd to any directory within your own home folder that is it will change all files and folders to lower case recursively please use with caution. It is a brilliant command line fix and especially useful for those multitudes of albums you have stored on your drive.

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

    You can specify a directory in place of the dot(.) after the find which denotes current directory or full path.

    I hope this solution proves useful the one thing this command does not do is replace spaces with underscores - oh well another time perhaps.

    0 讨论(0)
提交回复
热议问题