Reverse a String in Pure Bash Without rev
Reverse a string in pure Bash with a for loop and substring expansion. It handles UTF-8, but it took about 2 seconds for 20000 characters where rev took 2 milliseconds.
You want to reverse a string in a script, and the rev command may not be installed.
export LC_ALL=C.UTF-8
s='héllo wörld'
rev=
for ((i = ${#s} - 1; i >= 0; i--)); do rev+=${s:i:1}; done
echo "$rev"
echo "$s" | rev
long=$(printf 'x%.0s' {1..20000})
TIMEFORMAT='loop over 20000 characters: %Rs'
time { r=; for ((i = ${#long} - 1; i >= 0; i--)); do r+=${long:i:1}; done; }
TIMEFORMAT='rev over 20000 characters: %Rs'
time { rev <<< "$long" > /dev/null; }dlröw olléh
dlröw olléh
loop over 20000 characters: 2.151s
rev over 20000 characters: 0.002sThe loop walks the index from the last character to the first and appends ${s:i:1} each time. With a UTF-8 locale set, as LC_ALL=C.UTF-8 does here, Bash counts characters and not bytes, so héllo wörld comes out right. The timing is the point: appending in a loop took about 2.1 seconds for 20000 characters in this run, against 2 milliseconds for rev. Substring expansion is documented under Shell Parameter Expansion.
Use the loop only for short strings such as a name or a code, and call rev for anything long. In the C locale the same loop works on bytes and splits multibyte characters in half.