DEV Community

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

Posted on

3 1

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! ⌨️

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

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

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more