4

I've been trying with sed, and googling for the whole morning, and I can't seem to get this to work.

Is it possible with sed to lowercase text between two specific characters:

i.e.

SOMENAME=WOODSTOCK,
SOMEOTHERNAME=JIMMY,

can I lowercase WOODSTOCK and JIMMY (to woodstock and jimmy) on the basis they are between = and ,?

1
  • 1
    Does it have to be sed, or is awk e.g. also a possibility? Also, please explain whether the entire file you are trying to modify consists of lines as you show in the example, or if there are other text structures that may need special consideration.
    – AdminBee
    Jun 29, 2020 at 11:57

2 Answers 2

5

It is possible with GNU sed. Choose one of these two forms based on the greediness of the replacement.

sed 's|=.*,|\L&|' file
sed 's|=[^,]*,|\L&|' file

As the manual states, "\L turns the replacement to lowercase until a \U or \E is found". & is the text matched by the regex.


I have modified the sample file to show that you should wisely choose between the geedy =.*, and the non-greedy =[^,]*, regexes:

$ cat file
SOMENAME=WOODSTOCK,
SOMEOTHERNAME2=JIMMY,WOODSTOCK,FINISH
$ sed 's|=.*,|\L&|' file
SOMENAME=woodstock,
SOMEOTHERNAME2=jimmy,woodstock,FINISH
$ sed 's|=[^,]*,|\L&|' file
SOMENAME=woodstock,
SOMEOTHERNAME2=jimmy,WOODSTOCK,FINISH
3
  • this is awesome and exactly what I needed. thank you. I'm a dev, (as you can see on my SO profile) but I struggle with sed, any good resources to learn it you can recommend? thanks again.
    – Woodstock
    Jun 29, 2020 at 12:23
  • @Woodstock You're welcome! I learned it mainly by Sed - An Introduction and Tutorial. The GNU sed manual also seems pretty nice to learn, although I have only used it as a reference.
    – Quasímodo
    Jun 29, 2020 at 14:13
  • thanks a lot, super helpful!
    – Woodstock
    Jun 29, 2020 at 14:48
4

On any POSIX compliant awk, you can use the tolower() function

awk -v FS='=' 'BEGIN { OFS = FS } { $2 = tolower($2) }1 ' file

Use the mktemp() function to create a temp file to redirect the output of above command and then re-direct back to save in-place. Or use GNU awk >= 4.1 with -i inplace

Another variant of POSIX compliant version, using match() function would be to do

awk 'match($0, /=([^,]*),/) { str = substr($0, RSTART+1, RLENGTH-2); sub(str, tolower(str)) }1'
6
  • 1
    The problem is that I suspect the sample input given by the OP may not be a complete representation of the file's content, and that there may be other text components after the first , (that was probably also the same reason why @Quasimodo added the caveat about greedy/non-greedy regexes). Unfortunately, the OP has not clarified that point very well ...
    – AdminBee
    Jun 29, 2020 at 14:12
  • @AdminBee sorry, there is no extra info, file is just as shown
    – Woodstock
    Jun 29, 2020 at 14:47
  • @Woodstock I see, then Inian's solution is "the awk alternative" @Quasimodo asked for.
    – AdminBee
    Jun 29, 2020 at 15:11
  • @Inian I am curious: Why are you setting the FS via -v; is the -F option not portable? I thought only OFS needs to be set in this way (as in -v OFS='=' ...)
    – AdminBee
    Jun 29, 2020 at 15:14
  • @AdminBee: Yes you are right, POSIX says, they are functionally equivalent. As for why I did that, its just a style I use, no concrete reason behind
    – Inian
    Jun 29, 2020 at 15:19

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.