This is a faster variation of JaredTS486's answerJaredTS486's approach that uses native Bash capabilities (including Bash versions <4.0) to optimize his approach. It even seems to perform faster than
I've timed 1,000 iterations of each approach for a small string tr '[:lower:]' '[:upper:]'
on my machine!(25 characters) and a larger string (445 characters, consisting of the poem "The Robin" by Witter Bynner).
Timing results for 1,000 iterations of 25 characters:
Timing results for 1,000 iterations of 445 characters:
- 9 seconds for
tr '[:lower:]' '[:upper:]'
- 17 seconds for my approach
- 25 seconds for [Orwellophile's approach]
- 829 seconds for JaredTS486's approach
Solution:
#!/bin/bash
set -e
set -u
declare LCS="abcdefghijklmnopqrstuvwxyz"
declare UCS="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
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}"
}
echo "OUTPUT: [$( ucase 'Change Me To All Capitals' )]"
The approach is simple: while the input string has any remaining lowercase letters present, find the first one, and replace all instances of that letter with its uppercase variant. Repeat until all lowercase letters are replaced.
On my machine, the test string Change Me To All Capitals
requires 11 loops, and less than 6 seconds to execute 1,000 times, which is surprisingly faster than invoking tr '[:lower:]' '[:upper:]'
, which takes over 8 seconds to execute 1,000 times. JaredTS486's answer requires 650 loops and over 35 seconds to execute 1,000 times.
Note that the execution time drops from less than 6 seconds to less than 5 seconds when the logic is inlined directly within the source code, instead of embedded within a Bash function
that is then invoked via a string-interpolation subshell $( )
.