Portable way to switch text case from the command line

conversionposixtext;

Is there a way, portable across POSIX operating systems and locale-aware, to switch text case from the command line–that is replacing lower case letters by upper case ones and vice versa.

Using GNU sed, I can use that:

echo 'Yes, I Know IT!' | sed -E 's/([[:upper:]]*)([[:lower:]]*)/\L\1\U\2/g'
yES, i kNOW it!

Which works nicely with accented letters:

echo Élève | sed -E 's/([[:upper:]]*)([[:lower:]]*)/\L\1\U\2/g'
éLÈVE

But since it uses the \L and \U GNU extension is not portable.
And tr, on the other hand, does not properly handle accented letters on my Linux box:

echo 'Élève' | tr '[:lower:][:upper:]' '[:upper:][:lower:]'
ÉLèVE

Any solution?

Best Answer

If you'll accept perl, then this solution copied straight from Perl, using tr function to convert uppercase to lowercase and vice-versa at the same time? will work for you:

echo 'Hello Élève. It is beautiful!' |
    perl -Mopen=locale -Mutf8 -pe 's/([[:upper:]])|([[:lower:]])/defined $1 ? lc $1 : uc $2/eg'

hELLO éLÈVE. iT IS BEAUTIFUL!

I also wondered about using something like ( gsed ... || tr ... ) so that on systems with GNU's gsed it would take priority, but on other systems where tr was probably not GNU that would execute instead. (Non-GNU POSIX tr apparently handles multi-byte characters correctly.)