sed command from cmake does not change input file - sed

I want to modify src/some_file.txt before building my executable:
cmake_minimum_required(VERSION 3.5.1)
project(MyProject)
add_custom_target(run ALL
COMMAND sed -i "s#MY_PATH=\\(.*\\)#MY_PATH=${CMAKE_BINARY_DIR}/\\1#" ${CMAKE_CURRENT_SOURCE_DIR}/some_file.txt
)
add_executable(e main.cpp)
add_dependencies(e run)
src/some_file.txt has content:
MY_PATH=something
Targets run and e get build but src/some_file.txt remains unchanged. Why?

Either you're not using GNU sed or the file doesn't match the pattern.
My guess would be that you need to escape the backslashes again, but you don't need them anyway, just use:
sed -i 's#MY_PATH=#MY_PATH=${CMAKE_BINARY_DIR}/#'
Or simply
sed -i 's#MY_PATH=#&${CMAKE_BINARY_DIR}/#'
where & expands to the matched pattern. You should use single-quotes not double-quotes unless you specifically want the shell to expand variables.

Related

How to use SED to find multiple paths in the same line and replace them with a different path?

I have a file with multiple paths in the same line:
cat modules.dep
kernel/mm/zsmalloc.ko:
kernel/crypto/lzo.ko:
kernel/drivers/char/tpm/tpm_vtpm_proxy.ko: kernel/drivers/char/tpm/tpm.ko
kernel/drivers/block/virtio_blk.ko:
kernel/drivers/block/zram/zram.ko: kernel/mm/zsmalloc.ko
kernel/drivers/nvdimm/virtio_pmem.ko: kernel/drivers/nvdimm/nd_virtio.ko
kernel/drivers/nvdimm/nd_virtio.ko:
kernel/drivers/net/virtio_net.ko: kernel/drivers/net/net_failover.ko kernel/net/core/failover.ko
kernel/drivers/net/net_failover.ko: kernel/net/core/failover.ko
extra/virtio_gpu/virtio-gpu.ko: kernel/drivers/virtio/virtio_dma_buf.ko
extra/wlan_simulation/virt_wifi_sim.ko: kernel/drivers/net/wireless/virt_wifi.ko
I would like to change it to:
/lib/modules/zsmalloc.ko:
/lib/modules/lzo.ko:
/lib/modules/tpm_vtpm_proxy.ko: /lib/modules/tpm.ko
/lib/modules/virtio_blk.ko:
/lib/modules/zram.ko: /lib/modules/zsmalloc.ko
/lib/modules/virtio_pmem.ko: /lib/modules/nd_virtio.ko
/lib/modules/nd_virtio.ko:
/lib/modules/virtio_net.ko: /lib/modules/net_failover.ko /lib/modules/failover.ko
/lib/modules/net_failover.ko: /lib/modules/failover.ko
/lib/modules/virtio-gpu.ko: /lib/modules/virtio_dma_buf.ko
/lib/modules/virt_wifi_sim.ko: /lib/modules/virt_wifi.ko
But my attempt:
sed -i 's/\(.*\)\//\/lib\/modules\//g' modules.load
works only, if there is just one path per line.
How can I achieve this, via sed, with multiple paths per line?
I am using sed from BusyBox in D(ASH) Standalone.
BusyBox v1.32.1-Magisk (2021-01-21 00:17:27 PST) multi-call binary.
Usage: sed [-i[SFX]] [-nrE] [-f FILE]... [-e CMD]... [FILE]...
or: sed [-i[SFX]] [-nrE] CMD [FILE]...
-e CMD Add CMD to sed commands to be executed
-f FILE Add FILE contents to sed commands to be executed
-i[SFX] Edit files in-place (otherwise sends to stdout)
Optionally back files up, appending SFX
-n Suppress automatic printing of pattern space
-r,-E Use extended regex syntax
If no -e or -f, the first non-option argument is the sed command string.
Remaining arguments are input files (stdin if none).
This sed should work:
sed -E 's~[^[:blank:]]+/~/lib/modules/~g' modules.dep
/lib/modules/zsmalloc.ko:
/lib/modules/lzo.ko:
/lib/modules/tpm_vtpm_proxy.ko: /lib/modules/tpm.ko
/lib/modules/virtio_blk.ko:
/lib/modules/zram.ko: /lib/modules/zsmalloc.ko
/lib/modules/virtio_pmem.ko: /lib/modules/nd_virtio.ko
/lib/modules/nd_virtio.ko:
/lib/modules/virtio_net.ko: /lib/modules/net_failover.ko /lib/modules/failover.ko
/lib/modules/net_failover.ko: /lib/modules/failover.ko
/lib/modules/virtio-gpu.ko: /lib/modules/virtio_dma_buf.ko
/lib/modules/virt_wifi_sim.ko: /lib/modules/virt_wifi.ko
[^[:blank:]]+/ finds 1+ non-whitespace characters followed by a / thus matching longest string until it gets a / in each of the multiple string per line.

Replace string with $ from makefile with sed

I am trying to replace ${dbPassword} in a property file with a password including $ signs.
My command is the following, but I have no idea how to replace this properly.
run: #cat $(FILE_PATH) | sed -i .bak 's/$${dbPassword}/$(VARIABLE_WITH_PWD)/g' $(FILE_PATH)
Let's say my dbPassword is: 123$456$789
With this, I am getting the result: 123${dbPassword}456${dbPassword}789
Three problems:
Target and recipe on the same line. The recipe must be on the next line, indented with a hard tab.
You pass $(FILE_PATH) on stdin, and as a file argument to sed. Remove the cat pipe.
Shell variables (as opposed to make variables) are not substituted inside single quotes.
So you might want to try this instead:
.PHONY: run
run:
sed -i .bak "s/$${dbPassword}/$(VARIABLE_WITH_PWD)/g" $(FILE_PATH)
This assumes you have an environment variable, dbPassword and exported it prior to running make. If that is not the case, please provide your complete makefile.
I also have removed the # so you actually see what command make is executing. There's no point in wearing a blindfold while debugging your makefile.

(Gnu) sed command to change a matching part of a line

Is there a way in (Gnu) sed to replace all characters in a matching part of a string? For example I might have a list of file paths with several (arbitrary number of) paths in each line, e.g.:
/a/b/c/d/e /f/g/XXX/h/i /j/k/l/m
/n/o/p /q/r/s/t/u /v/x/x/y
/z/XXX/a/b /c/d/e/f
I would like to replace all the slashes in paths containing XXX keping all the others untouched, e.g.:
/a/b/c/d/e #f#g#XXX#h#i /j/k/l/m
/n/o/p /q/r/s/t/u /v/x/x/y
#z#XXX#a#b /c/d/e/f
Unfortunately I cannot come up with a solution. Maybe it's even impossible with sed. But I'm curious if somebody find a way to solve the problem.
We can replace any / preceding XXX with no intervening spaces like this:
# Using extended regex syntax
s!/([^ ]*XXX)!#\1!
It's a very similar substitution for those that follow XXX.
Putting them together in a loop makes this program:
#!/bin/sed -rf
:loop
s!/([^ ]*XXX)!#\1!
s!(XXX[^ ]*)/!\1#!
tloop
Output:
/a/b/c/d/e #f#g#XXX#h#i /j/k/l/m
/n/o/p /q/r/s/t/u /v/x/x/y
#z#XXX#a#b /c/d/e/f
That said, it might be simpler to use a pipeline, to break the file paths into individual lines and then reassemble them after the substitution:
sed -e 's/ *$//;s/ */&\n/g' \
| sed -e '/XXX/y,/,#,' \
| sed -e ':a;/ $/{N;s/\n//;ba}'

Replace a word with another set of strings in a UNIX file

When I try to replace a string using sed command it works perfectly fine.
For eg :
When i used the below sed command:
sed 's/DB_ALTER/DB_REPRISE/g' /product/dwhrec1/abc.ksh > /product/dwhrec1/abc1.ksh
This command works perfectly fine and replace all the "DB_ALTER" with "DB_REPRISE" and writes the result to abc1.ksh script.
But when I place all such values in a file. for eg:
cat Repla.txt
DB_ALTER
DB_CMD
DB_GEST_COMM
for i in `cat Repla.txt`
do
sed 's/$i/DB_REPRISE/g' /product/dwhrec1/abc.ksh > /product/dwhrec1/abc1.ksh
done
But this does not work. In my file Repla.txt is just an example. In actual it has many values.
Can anyone please help me on this command or suggest some alternative.
Thanks
There are two problems with your script. The first is that the $i variable appears within single quotes. That means that bash will not substitute for the value of i. It needs to be in double-quotes.
Secondly, every time that you run sed, it overwrites the previous abc1.ksh file. You should copy abc.ksh to abc1.ksh and then modify in place abc1.ksh as many times as needed:
cp abc.ksh abc1.ksh
for i in `cat Repla.txt`; do
sed -i'' "s/$i/DB_REPRISE/g" abc1.ksh
done
The -i flag to sed causes it to modify the file in place.
Also, bash will apply word splitting to cat Repla.txt. This can surprise people who were expecting it to work line-by-line, not word-by-word.
Workaround in case your sed does not support -i
The sed on both linux (GNU) and Mac OSX (BSD) support -i. If your sed does not, try:
cmd=
for i in `cat Repla.txt`; do
[ "$cmd" ] && cmd="$cmd;"
cmd="$cmd s/$i/DB_REPRISE/g"
done
sed "$cmd" abc.ksh >abc1.ksh
The above puts all the substitution commands that you need in a single shell variable. This way, sed only needs to be run once and -i is not used.
Another option
If it is acceptable to overwrite the source file, then:
for i in $(cat Repla.txt)
do
sed 's/'$i'/DB_REPRISE/g' abc.ksh >abc1.ksh
mv -f abc1.ksh abc.ksh
done
The above puts in single quotes all of the sed command except for the part that we want the shell to expand. This is not needed in this example but could be useful if your replacement text had shell-active characters. The above also uses the more modern $(...) in place of backquotes for command substitution.
If $i were to contain spaces (it doesn't here), we would need to enclose it in double-quotes to protect it against shell word splitting as in:
for i in $(cat Repla.txt)
do
sed 's/'"$i"'/DB_REPRISE/g' abc.ksh >abc1.ksh
mv -f abc1.ksh abc.ksh
done

Combining two sed commands

I have a file r. I want to replace the words File and MINvac.pdb in it with nothing. The commands I used are
sed -i 's/File//g' /home/kanika/standard_minimizer_prosee/r
and
sed -i 's/MINvac.pdb//g' /home/kanika/standard_minimizer_prosee/r
I want to combine both sed commands into one, but I don't know the way. Can anyone help?
The file looks like this:
-6174.27 File10MINvac.pdb
-514.451 File11MINvac.pdb
4065.68 File12MINvac.pdb
-4708.64 File13MINvac.pdb
6674.54 File14MINvac.pdb
8563.58 File15MINvac.pdb
sed is a scripting language. You separate commands with semicolon or newline. Many sed dialects also allow you to pass each command as a separate -e option argument.
sed -i 's/File//g;s/MINvac\.pdb//g' /home/kanika/standard_minimizer_prosee/r
I also added a backslash to properly quote the literal dot before pdb, but in this limited context that is probably unimportant.
For completeness, here is the newline variant. Many newcomers are baffled that the shell allows literal newlines in quoted strings, but it can be convenient.
sed -i 's/File//g
s/MINvac\.pdb//g' /home/kanika/standard_minimizer_prosee/r
Of course, in this limited case, you could also combine everything into one regex:
sed -i 's/\(File\|MINvac\.pdb\)//g' /home/kanika/standard_minimizer_prosee/r
(Some sed dialects will want this without backslashes, and/or offer an option to use extended regular expressions, where they should be omitted. BSD sed, and thus also MacOS sed, demands a mandatory argument to sed -i which can however be empty, like sed -i ''.)
Use the -e flag:
sed -i -e 's/File//g' -e 's/MINvac.pdb//g' /home/kanika/standard_minimizer_prosee/r
Once you get more commands than are convenient to define with -es, it is better to store the commands in a separate file and include it with the -f flag.
In this case, you'd make a file containing:
s/File//g
s/MINvac.pdb//g
Let's call that file 'sedcommands'. You'd then use it with sed like this:
sed -i -f sedcommands /home/kanika/standard_minimizer_prosee/r
With only two commands, it's probably not worthwhile using a separate file of commands, but it is quite convenient if you have a lot of transformations to make.