How to change the format of substitution variables in a template
-
04-07-2019 - |
Question
I need to to iterate over the files in a directory and perform the following replacement.
Before:
Hello ${USER_NAME}, you live at ${HOME_ADDRESS}. It is now ${TIME}
After:
Hello ${userName}, you live at ${homeAddress}. It is now ${time}
The number of different tokens that appear within ${} is large, so it's not really feasible to run:
find . -name '*' -exec sed -i 's/${USER_NAME}/${userName}/g' {} \;
find . -name '*' -exec sed -i 's/${TIME}/${time}/g' {} \;
etc.
I'm hoping it's possible to perform this replacement using a single command, that looks something like:
find . -name '*' -exec sed 's/XXX/YYY/g' {} \;
But I can't figure out what to substitute for XXX and YYY. Is it possible to do this in a single command?
Cheers, Donal
Solution
The -i
flag to sed will edit a file in-place. For XXX and YYY, you would use something like:
sed -i 's/USER_NAME/userName/g'
and so on.
Update: I see that your question was really about changing "USER_NAME" into "userName" automatically. You could try this Perl script:
sub convert {
my $r = lc $_[0];
$r =~ s/_(.)/\U$1\E/g;
return $r;
}
while (<>) {
s/\${([A-Z_]+)}/\${@{[convert $1]}}/g;
print;
}
Run it like this:
perl -i convert.pl inputfile.txt
Sample output:
$ cat inputfile.txt
Hello ${USER_NAME}, you live at ${HOME_ADDRESS}. It is now ${TIME}
$ perl -i convert.pl inputfile.txt
$ cat inputfile.txt
Hello ${userName}, you live at ${homeAddress}. It is now ${time}
OTHER TIPS
Formatted for clarity:
sed -i '/^Hello/ { s/\$\{USER_NAME\}/\$\{userName\}/g
s/\$\{HOME_ADDRESS\}/\$\{homeAddress\}/g
s/\$\{TIME\}/\$\{time\}/g
}'
Where /^Hello/
identifies the lines you wish to act on (make it more specific if needed) and the rest substitutes each variable name.
If writing this into a script consider the use of a HERE document to keep the formatting and make it easier to read and update...
The answer above works really well. For completeness, I might add that you can do:
sed '/^Hello/ { s/\$\{USER_NAME\}/\$\{userName\}/g' <filename> \
| sed 's/\$\{HOME_ADDRESS\}/\$\{homeAddress\}/g' \
| sed 's/\$\{TIME\}/\$\{time\}/g'
They're functionally identical (except that mine dumps to stdout; you'll have to put it somewhere (but you get to keep the original in case, like e, you mess up regularly on your regexps). I like my formulation just because I can start with the one sed command, then add on more with
!! | sed 'yet-enother-regexp'
Arrow keys? vi-mode? Who needs that stuff? :)