83

I have temp file with some lower-case and upper-case contents.

Input

Contents of my temp file:

hi
Jigar
GANDHI
jiga

I want to convert all upper to lower.

Command

I tried the following command:

sed -e "s/[A-Z]/[a-z]/g" temp

but got wrong output.

Output

I want it as:

hi
jigar
gandhi
jiga

What needs to be in the substitute part of argument for sed?

119

If your input only contains ASCII characters, you could use tr like:

tr A-Z a-z < input 

or (less easy to remember and type IMO, but not limited to ASCII latin letters):

tr '[:upper:]' '[:lower:]' < input

if you have to use sed:

sed 's/.*/\L\1/g' < input

(here assuming the GNU implementation).

  • 3
    Please note that \L is a GNU extension. – Anthon Dec 5 '14 at 7:48
  • \L works good for me so far. En light the point that you are trying to make GNU extension – JigarGandhi Dec 5 '14 at 7:56
  • 2
    @JigarGandhi. sed is a Unix command. Different systems have different variants with different behaviour and functionality. Thankfully, nowadays, there's a standard that most conform to so you can count on a minimum set of features common to all. \L is not among them and was introduced by GNU sed (matches the same operator in standard ex/vi) and is generally not available in other implementations. – Stéphane Chazelas Dec 5 '14 at 13:25
  • 9
    Note that some tr implementations like GNU tr don't work properly in multi-byte locales (most of them are nowadays, try echo STÉPHANE | tr '[:upper:]' '[:lower:]' for instance). On GNU systems, you may prefer the sed variant or awk's tolower(). – Stéphane Chazelas Dec 5 '14 at 13:29
  • 5
    Slight correction: sed 's/.*/\L&/g' < input. The \1 reference to the matched substring won't work unless you specify the substring with parenthesis as wurtle does in his. However, it's slightly cleaner to use & to represent the whole match, as shown – Edward Brown Nov 4 '16 at 15:30
29

Using vim, it's super simple:

$ vim filename
gg0guGZZ

Opens the file, gg goes to the first line, 0, first column. With guG, lowers the case of all the characters until the bottom of the file. ZZ saves and exits.

It should handle just about anything you throw at it; it'll ignore numbers, it'll handle non ASCII.

If you wanted to do the opposite, turn the lower cased letters into upper case, swap the u out for a U: gg0gUGZZ and you're set.

  • 13
    Lol "super simple" – blambert Feb 17 '17 at 21:50
  • this obviously doesn't scale well for many files – Corey Goldberg Nov 25 '17 at 13:40
  • my most favorite answer thus far!!!! – Mona Jalal Apr 21 '18 at 22:50
  • 1
    @CoreyGoldberg vim file1 file2 fileetc and then something like :bufdo gg0guG:w<CR> would probably work for any number of files. Have not tested that though! – TankorSmash Apr 22 '18 at 0:18
  • @TankorSmash that still doesn't scale to a large number of files – Corey Goldberg Apr 22 '18 at 15:39
17

I like dd for this, myself.

<<\IN LC_ALL=C 2>/dev/null \
dd conv=lcase
hi
Jigar 
GANDHI
jiga
IN

...gets...

hi
jigar
ghandi
jiga

The LC_ALL=C is to protect any multibytes in input - though any multibyte capitals will not be converted. The same is true for (GNU) tr - both apps are prone to input mangling in any non-C locale. iconv can be combined with either for a comprehensive solution.

The 2>/dev/null redirect discards dd's default status report - and its stderr. Without it dd would follow completion of a job like the above w/ printing information like how many bytes were processed and etc.

  • This solution is way faster than tr when handling large files, thanks! – WhiteWinterWolf Aug 18 '16 at 13:02
12

You can also use Perl 5:

perl -pe '$_=lc' temp

The option -p tells perl to run the specified expression once for each line of input, printing the result, i.e. the final value of $_. -e indicates that the program will be the next argument, as opposed to a file containing the script. lc converts to lowercase. Without an argument, it will operate on $_. And $_= saves that again so it will get printed.

A variation of that would be

perl -ne 'print lc' temp

Using -n is like -p except that $_ won't get printed in the end. So instead of saving to that variable, I'm including an explicit print statement.

One benefit of Perl in contrast to sed is that you don't need any GNU extensions. There are projects which have to be compatible with non-GNU environments but which also already have Perl a s a dependency. Compared with tr, it might be that Perl lc can be more easily made locale-aware. See the perllocale man page for details.

9

You need to capture the matched pattern and then use it in the replacement with a modifier:

sed 's/\([A-Z]\)/\L\1/g' temp

The \(...\) "captures" the enclosing matched text, the first capture goes to \1, the next to \2, etc. The numbering is according to opening brackets in case of nested captures.

The \L converts the captured pattern to lower case, there's also \U for upper case.

  • 3
    you dont need to do this - the whole pattern is always caught in & – mikeserv Dec 5 '14 at 9:41
  • True, but then I would have missed the opportunity to explain capturing matches :-) – wurtel Dec 5 '14 at 12:47
0

Further to MvG's answer, you could also use Perl 6:

perl6 -pe .=lc temp

Here $_ is implicit, and you don't need the single quotes to protect it from expansion by the shell ($_ being a special Bash parameter; see: https://www.gnu.org/software/bash/manual/html_node/Special-Parameters.html)

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.