My question is how can I convert all text from uppercase to lowercase and vice versa? That is to change the cases of all the letters. It has to be done with a sed
replacement somehow.
7 Answers
Here is a straight way in sed
:
$ echo qWeRtY | sed -e 'y/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/'
QwErTy
or a shorter way with GNU sed
, working with any character for which a lowercase<->uppercase conversion exists in your locale:
$ echo qWeRtY | sed -E 's/([[:lower:]])|([[:upper:]])/\U\1\L\2/g'
QwErTy
if you can use another tools, like:
perl
(limited to ASCII letters):
$ echo qWeRtY | perl -pe 'y/[a-z][A-Z]/[A-Z][a-z]/'
QwErTy
perl
(more generally):
$ echo 'αΒγ' | perl -Mopen=locale -pe 's/(\p{Ll})|(\p{Lu})/uc($1).lc($2)/ge'
ΑβΓ

- 544,893

- 153,898
-
3Your second one assumes a GNU
sed
and alternate case in the input. Usesed -re 's/([[:lower:]]?)([[:upper:]]?)/\U\1\L\2/g'
instead (still GNU specific). The first one only converts the 26 ASCII latin letters, while the second converts any letter recognised as such by your locale. Thetr
one only makes sense in ASCII locales. Theperl
one only works for ASCII latin letters. – Stéphane Chazelas Jun 08 '14 at 20:47
POSIXly, that can't be done with sed
except by providing the complete set of letters you want to transliterate as @cuonglm has shown.
It could be done with tr
though, and that's what tr
is for (transliterate):
tr '[:lower:][:upper:]' '[:upper:][:lower:]'
However, on Linux, it's got limitations. Of the 3 tr
implementations commonly found on Linux-based systems:
- with GNU
tr
, that only works for single-byte character sets. For instance, onStéphane Chazelas
in UTF-8 locales, that givessTéPHANE cHAZELAS
instead ofsTÉPHANE cHAZELAS
. That's a known limitation of GNUtr
. - with
tr
from the heirloom toolchest, that doesn't work (you getstéphane chazelas
). - That's not the kind of thing busybox
tr
will do.
On FreeBSD that works OK though. You'd expect it to work OK in certified Unix systems as well.
The bash
shell has a dedicated operator for that:
in=AbCdE
out=${in~~}
With zsh -o extendedglob
:
out=${in//(#b)(([[:lower:]])|([[:upper:]]))/${(U)match[2]}${(L)match[3]}}

- 544,893
-
So in desktop world only OSX does it? Why can't it work? Is it just the different implementations as it seems there is a constant offset in the hex value between the lower case version of the accented char and it's uppercase counterpart? – Jun 08 '14 at 23:31
-
1@illuminÉ, not sure what you mean by desktop world. AFAICS, the problem is with GNU, most Unices have "desktops". Apart from ASCII and some iso8859 charsets, I'm not aware that you can generalise the hex offset thing, and that wouldn't make sense with encodings like UTF-8. For instance in UTF-8, uppercase
ⴠ
(e2 b4 a0) isჀ
(e1 83 80); bothi
(69) andı
(c4 b1) haveI
(49) as uppercase (except in Turkish locales wherei
becomesİ
). The reason it doesn't work with GNUtr
is that GNUtr
works with bytes and not characters. – Stéphane Chazelas Jun 09 '14 at 05:34 -
I sort of meant mainstream but it doesn't make sense really so thanks for the heads up. I just looked at the French accented chars(and really just "é") and made very simplistic assumptions, forgetting again that it's about bytes. But the heirloom one? I'll go read that answer again! – Jun 09 '14 at 05:43
-
1@illuminÉ, for heirloom, it's a different issue, it seems it only supports only one occurrence of
[:lower:]
or[:upper:]
(so the first one is ignored). Even in French,œ -> Œ
isc5 93 -> c5 92
in UTF-8 andbd -> bc
in iso8859-15. – Stéphane Chazelas Jun 09 '14 at 05:49
If your main objective is to convert a file from lowerclass to upperclass,
why dont you use tr
and STDOUT
to convert your file:
$cat FILENAME | tr a-z A-Z > FILENAME2
Where FILENAME
is your original file.
Where FILENAME2
is your converted output file.

- 5,882

- 31
-
It didn't work with accented chars, like
é
for example (at least in my file). – Sigur Nov 19 '19 at 21:02
Though this has the same limitations already mentioned as the tr
solution offered by Stéphane Chazelas, it is another way to do it:
{ echo QWERTYqwerty | dd conv=lcase
echo QWERTYqwerty | dd conv=ucase
} 2>/dev/null
OUTPUT
qwertyqwerty
QWERTYQWERTY
I dump stderr
into /dev/null
there because dd
also provides statistics of all its operations on the 2
file descriptor. This can be useful depending on what you're doing, but wasn't for this demonstration. All of the other stuff you can do with dd
still applies, for instance:
echo QWERTYqwerty | dd bs=1 cbs=6 conv=unblock,ucase 2>/dev/null
OUTPUT:
QWERTY
QWERTY

- 58,310
-
It doesn't swap the case though (as in
aBc
is not converted toAbC
). – Stéphane Chazelas Jun 09 '14 at 05:24 -
1@StéphaneChazelas - true, but unless I've misunderstood, that wasn't the question, was it? – mikeserv Jun 09 '14 at 06:32
using awk
:
awk '{print tolower($0)}' file.txt | tee file.txt

- 2,051
-
you sure this is going to work?
>file.txt
would start off by truncating the file – iruvar Sep 22 '16 at 18:04 -
2
ruby
has a string method for that, similar usage from command line like perl
$ echo 'qWeRtY' | ruby -pe '$_.swapcase!'
QwErTy
See also ruby-doc Encoding
$ ruby -e 'puts Encoding.default_external'
UTF-8
$ echo 'αΒγ' | ruby -pe '$_.swapcase!'
ΑβΓ

- 12,008
Keep simple thing simple. The filter designed to translate characters is tr
.
echo 1ude1UDE | tr [:upper:][:lower:] [:lower:][:upper:]

- 1
-
2That's a broken (because of the missing quotes around the globbing operators) version of an answer already given 2 years earlier – Stéphane Chazelas Aug 25 '17 at 12:23
tr
would be more suitable thansed
. – choroba Jun 08 '14 at 19:25