DEV Community

Cover image for Quiz: in-file string replacement using bash
Julien Dephix
Julien Dephix

Posted on

Quiz: in-file string replacement using bash

Hello, coders! 💻

Today's quiz taken from a real world task is:

replace a string in a file using bash.

I challenge you!

Pre-requisites

We have a dynamically generated variable newPath:
newPath=/new/path/$(date +"%Y%m%d%H%M%S")/file.json

We want to change the value of PATH_TO_FILE with the value of newPath in /app/.env.

File before replacement:

# /app/.env
# there could be lines here
PATH_TO_FILE=/path/to/file.json
# there could be lines here too
Enter fullscreen mode Exit fullscreen mode

File after replacement:

# /app/.env
# there could be lines here
PATH_TO_FILE=/new/path/20220630081234/file.json
# there could be lines here too
Enter fullscreen mode Exit fullscreen mode

Starter script

#!/usr/bin/env bash

newPath=/new/path/$(date +"%Y%m%d%H%M%S")/file.json

# your code here
Enter fullscreen mode Exit fullscreen mode

My take on this

Click to see my solution
#!/usr/bin/env bash

newPath=/new/path/$(date +"%Y%m%d%H%M%S")/file.json

sed -iE "s|(PATH_TO_FILE).*|\1=${newPath}|g" /app/.env
Enter fullscreen mode Exit fullscreen mode

-i option means in place. So any change made to /app/.env will be saved.

-E stands for extended regular expressions.

Traditionally we use / when replacing things : s/to_be_replaced/replacement/g for instance.
Since we're dealing with a file path we would need to escape slashes in newPath but there's a better way: use a different separator. I'm using | here but you can use @ if you prefer.

\1 holds what was captured by the parenthesis which is PATH_TO_FILE in our case.

And that's it!

Comments on how to improve this solution are most welcome.

Happy coding! ⌨️

Latest comments (4)

Collapse
 
moopet profile image
Ben Sinclair • Edited

I'd maybe add a constraint that the variable definition can only be preceded by whitespace, and ends in an equals sign:

sed -iE "s|^\s*(PATH_TO_FILE)=.*|\1=${newPath}|g" /app/.env
Enter fullscreen mode Exit fullscreen mode

This would exclude matching variables like ANOTHER_PATH_TO_FILE_FINAL_COPY_2 and would stop matching commented-out lines like # PATH_TO_FILE=/foo.

Also I think that it depends which sed you're using. GNU sed will work, but BSD sed needs you to specify a backup file when doing in-file replacements.

Collapse
 
joolsmcfly profile image
Julien Dephix

True that!

Wouldn't s|^(PATH_TO_FILE)=.* be enough though?

Collapse
 
moopet profile image
Ben Sinclair • Edited

I'd want to add the whitespace to cope with indentation. It's not particularly important for this case, but you might have something like this:


if [ "$ENV" = "development" ]; then
    PATH_TO_FILE=/foo/bar.json
else
    PATH_TO_FILE=/foo/baz.json
fi
Enter fullscreen mode Exit fullscreen mode
Thread Thread
 
joolsmcfly profile image
Julien Dephix

Gotcha, yeah in that case \s* makes sense.

Thanks for your input.