Replace string containing variable name with sed in makefile - sed

I want to replace a string in Makefile by another one using sed:
* old string: $(ISM_DEPTH)/obj/lib/mylib.a
* new string: $(ENVIRONMENT_ROOT)/lib/
So, I used this command:
sed -e 's,$(ISM_DEPTH)/obj/lib/mylib.a,$(ENVIRONMENT_ROOT)/lib/,g' -i Makefile
The problem is that sed will replace $(ISM_DEPTH) and $(ENVIRONMENT_ROOT) by their values and I don't wont to do that.

You need to escape the $ character. To do so in Makefile it's needed to write double dollar - $$.:
sed -e 's,$$(ISM_DEPTH)/obj/lib/mylib.a,$$(ENVIRONMENT_ROOT)/lib/,g' -i Makefile

Related

Using sed to replace to a var with special characters

I want to replace a placeholder on a file <<string>> in the example to the contents of a var that has several special characters.
file.txt
My string: <<string>>
script.sh
STRING="something-else;device=name.of.device;key=abcd1234/wtp="
sed -i "s/<<string>>/${STRING}/g" file.txt
I get this error:
sed: -e expression #1, char 165: unknown option to `s'
I already use this sed command for other vars that do not have special characters. Any way to escape the var ${STRING} entirely?
You can't do this job easily and robustly with sed, see Is it possible to escape regex metacharacters reliably with sed. Instead just use a tool like awk that understands literal strings:
$ string='~`!##$%^&*()-_+={[}]|\:;"'\''<,>.?/\1'
$ echo "$string"
~`!##$%^&*()-_+={[}]|\:;"'<,>.?/\1
$ string="$string" awk -i inplace 'match($0,/(.*)(<<string>>)(.*)/,a){ $0=a[1] ENVIRON["string"] a[3] } 1' file.txt
$ cat file.txt
My string: ~`!##$%^&*()-_+={[}]|\:;"'<,>.?/\1
That above will work for any characters (or backreference substrings like \1) that string might contain because it's simply using a literal string operation (concatenation) for the replacement.
It's using GNU awk for -i inplace just the same as your original script used GNU sed for -i.
Don't use all upper case for non-exported variable names by the way to avoid clashes with exported and built-in variables and not obfuscate your code by making it look like you're using exported variables, see Correct Bash and shell script variable capitalization.
Note that if you have multiple <<whatever>> placeholders you can easily parameterize the above, e.g.:
$ foo='Now is the Winter'
$ bar='Of our discontent'
$ cat file.txt
My foo string: <<foo>>
My bar string: <<bar>>
$ foo="$foo" bar="$bar" awk -i inplace 'match($0,/(.*)<<(\w+)>>(.*)/,a) && (a[2] in ENVIRON){ $0=a[1] ENVIRON[a[2]] a[3] } 1' file.txt
$ cat file.txt
My foo string: Now is the Winter
My bar string: Of our discontent
If you don't want to set foo and bar on the awk command line you can export them before it, or read them from a config file or a here-doc or ... - lots of options.
Since STRING contains a /, you should use a other delimiter, for example, you can use ^ like so:
sed 's^<<string>>^'"$STRING"'^g' file.txt
The quoting logic (''""'') is explained nicely on this SO answer.
Example on my locale machine:
$
$ cat file.txt
My string: <<string>>
$
$
$ STRING="something-else;device=name.of.device;key=abcd1234/wtp="
$
$
$ sed -i 's^<<string>>^'"$STRING"'^g' file.txt
$
$ cat file.txt
My string: something-else;device=name.of.device;key=abcd1234/wtp=
$
$

SED inplace file change inside make - How?

sed inplace change on a file is not working inside Make object.
I want to replace a line in a file with sed called in a make object. But it does not seem to be working. How can I fix this?
change_generics:
ifeq ($(run_TESTNAME), diagnostics)
ifeq ($(run_TESTCASE), 1)
sed -i -e "s/SIM_MULTI\==[a-z,A-Z]*/SIM_MULTI=TRUE/" ./generics.f
else ifeq ($(TESTCASE), 2)
sed -i -e "s/SIM_MISSED\==[a-z,A-Z]*/SIM_MISSED=TRUE/" ./generics.f
endif
endif
I would like the generics.f file changed with that one line change. But it remains the same as the original. The sed command works outside make.
I can't reproduce this using GNU sed 4.2.2 and GNU make 3.82, or at least, I can't reproduce any scenario where the same sed command works from the command line but not in a Makefile.
Simpler Makefile:
all:
# Contrived just so I can test your 2 sed commands.
sed -i -e "s/SIM_MULTI\==[a-z,A-Z]*/SIM_MULTI=TRUE/" ./generics.f
sed -i -e "s/SIM_MISSED\==[a-z,A-Z]*/SIM_MISSED=TRUE/" ./generics.f
Sample file content in generics.f:
SIM_MULTI=foo
SIM_MISSED=bar
Testing:
$ make all
sed -i -e "s/SIM_MULTI\==[a-z,A-Z]*/SIM_MULTI=TRUE/" ./generics.f
sed -i -e "s/SIM_MISSED\==[a-z,A-Z]*/SIM_MISSED=TRUE/" ./generics.f
Confirmed that both sed commands fail to edit a file with this content.
To fix:
Probably, you need to simply remove the \= from your regular expression. The backslash there has no effect, and causes your regex to simply match two equals signs ==. Thus this works:
all:
sed -i 's/SIM_MULTI=[a-zA-Z]*/SIM_MULTI=TRUE/' ./generics.f
sed -i 's/SIM_MISSED=[a-zA-Z]*/SIM_MISSED=TRUE/' ./generics.f
Testing:
$ make all
sed -i 's/SIM_MULTI=[a-zA-Z]*/SIM_MULTI=TRUE/' ./generics.f
sed -i 's/SIM_MISSED=[a-zA-Z]*/SIM_MISSED=TRUE/' ./generics.f
$ cat generics.f
SIM_MULTI=TRUE
SIM_MISSED=TRUE
Further explanation:
There is no need to specify -e there.
There is no need to enclose the script in double quotes, which is riskier because it allows the contents to be modified by the shell.
The bug appears to be \= and I deleted those characters, as mentioned above.
Note that I removed the comma , as well in [a-z,A-Z]. I think that probably isn't what you meant, and it would cause a class of characters including a-z, A-Z and a comma , to be matched by the regex. (And if it is what you mean, you might consider writing it as [a-zA-Z,] as that would be less confusing.)
If this has not resolved your issue, I would need to know things like:
What is the version of your sed.
What is the contents in generics.f.
POSIX/GNU sed have c for "change":
sed -i '/SIM_MULTI=/c\SIM_MULTI=TRUE'
sed -i '/SIM_MISSED=/c\SIM_MISSED=TRUE'

Sed find and replace Cpp file(.C)

I am having issues of editing huge C++ file where I am using sed to convert List(something) to List<something> why I am doing this because our List has been converted to template.
Command I have written in small shell file is like this
sed -i '/List/s/(/</g' $1
sed -i '/List/s/)/>/g' $1
But this command is converting the whole line associated with List to angular braces like,
some_Fun(List(something)) to some_Fun<List<something>>
I don't want sed to change some_Fun<> , sed should keep some_Fun() and change only List() to List<>.
You can use this sed:
sed 's/\(List\)(\([^)]*\))/\1<\2>/g' file
(OR)
sed 's/List(\([^)]*\))/List<\1>/g' file

how to find replace value with whitespace using sed in a bash script

I have values in a file like this ' value-to-remove '(without the ' characters). I want to use sed to run through the file and replace the values including the space before and after. I am running this via a bash script.
How can I do this?
The sed command I'm using at the moment replaces the values but leaves behind the two spaces.
sed -i 's/ '$value' / /g' test.conf
In script I have
sed -i -e 's/\s'$DOMAIN'-'$SITE'\s/\s/g' gitosis.conf
echoed as
sed -i -e s/\sffff.com-eeee\s/\s/g test.conf
Not working though.
IMHO your sed does not know '\s', so use [ \t], and use double quotes, otherwise your variables will not expand. e.g.:
sed -i -e "s/[ \t]'$DOMAIN'-'$SITE'[ \t]/ /g" gitosis.conf
Let me know if this is what you need
echo 'Some values to remove value-to-remove and more' | sed -e 's/\svalue-to-remove\s/CHANGED/g'
output: Some values to removeCHANGEDand more

sed error - unterminated substitute pattern

I am in directory with files consisting of many lines of lines like this:
98.684807 :(float)
52.244898 :(float)
46.439909 :(float)
and then a line that terminates:
[chuck]: cleaning up...
I am trying to eliminate :(float) from every file (but leave the number) and also remove that cleaning up... line.
I can get:
sed -ie 's/ :(float)//g' *
to work, but that creates files that keeps the old files. Removing the -e flag results in an unterminated substitute pattern error.
Same deal with:
sed -ie 's/[chuck]: cleaning up...//g' *
Thoughts?
sed -i '' -e 's/:(float)//' -e '/^.chuck/d' *
This way you are telling sed not to save a copy (null length backup extention to -i) and separately specifying the sed commands.
sed -ie expression [files...]
is equivalent to:
sed -ie -e expression [files...]
and both mean apply expression to files, overwriting the files, but saving the old files with an "e" as the backup suffix.
I think you want:
sed -i -e expression [files...]
Now if you're getting an error from that there must be something wrong with your expression.
your numbers are separated with (float) by the : character. Therefore, you can use awk/cut to get your numbers. Its simpler than a regex
$ head -n -1 file | awk -F":" '{print $1}'
98.684807
52.244898
46.439909
$ head -n -1 file | cut -d":" -f1
98.684807
52.244898
46.439909
Solution :
sed -i '' 's/ :(float)//g' *
sed -i '' 's/[chuck]: cleaning up...//g' *
Explanation :
I can get:
sed -ie 's/ :(float)//g' *
to work, but that creates files that keeps the old files.
That's because sed's i flag is supposed to work that way
-i extension
Edit files in-place, saving backups with the specified extension. If a zero-length extension is given, no backup will be saved.
In this case e is being interpreted as the extension you want to save your backups with. So all your original files will be backed up with an e appended to their names.
In order to provide a zero-length extension, you need to use -i ''.
Note: Unlike -i<your extension>, -i'' won't work. You need to have a space character between -i and '' in order for it to work.
Removing the -e flag results in an unterminated substitute pattern error.
When you remove the e immediately following -i, i.e.
sed -i 's/ :(float)//g' *
s/ :(float)//g will now be interpreted as the extension argument to i flag. And the first file in the list of files produced by shell expansion of * is interpreted as a sed function (most probably s/regular expression/replacement/flags function) You can verify this by checking the output of
sedfn=$(echo * | cut -d' ' -f1); [[ ${sedfn:0:1} == "s" ]]; echo $?
If the output of the above chain of commands is 0, our assumption is validated.
Also in this case, if somehow the first filename qualifies as a valid s/regular expression/replacement/flags sed function, the other filenames will be interpreted as regular files for sed to operate on.
sed -i -e 's/ :(float)//g' *
Check to see if you have any odd filenames in the directory.
Here is one way to duplicate your error:
$ touch -- "-e s:x:"
$ ls
-e s:x:
$ sed -i "s/ :(float)//g' *
sed: -e expression #1, char 5: unterminated `s' command
One way to protect against this is to use a double dash to terminate the options to sed when you use a wild card:
$ sed -i "s/ :(float)//g' -- *
You can do the same thing to remove the file:
$ rm "-e s:x:"
rm: invalid option -- 'e'
$ rm -- "-e s:x:"