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'

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:]'

Any solution?

  • Does your POSIX requirement exclude perl? (This is a pragmatic question, not a purist one, because I know that PCRE are not included within POSIX.)
    – roaima
    Sep 17, 2018 at 22:16
  • 1
    @roaima I though about Perl, but I would have preferred a solution using only the standard utilities: pubs.opengroup.org/onlinepubs/9699919799/idx/utilities.html However, if there is no such solution, any "widely available" solution should do the trick... Sep 17, 2018 at 22:42

1 Answer 1


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'


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.)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.