Hello, coders! π»
Today's quiz taken from a real world task is:
replace a string in a file using bash.
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
File after replacement:
# /app/.env
# there could be lines here
PATH_TO_FILE=/new/path/20220630081234/file.json
# there could be lines here too
Starter script
#!/usr/bin/env bash
newPath=/new/path/$(date +"%Y%m%d%H%M%S")/file.json
# your code here
My take on this
Traditionally we use And that's it! Comments on how to improve this solution are most welcome.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
-i
option means in place. So any change made to /app/.env
will be saved.-E
stands for extended regular expressions./
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.
Happy coding! β¨οΈ
Top comments (4)
I'd maybe add a constraint that the variable definition can only be preceded by whitespace, and ends in an equals sign:
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.True that!
Wouldn't
s|^(PATH_TO_FILE)=.*
be enough though?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:
Gotcha, yeah in that case
\s*
makes sense.Thanks for your input.