Sed replace text - sed

I need to replace text with single quotes with sed and I can't get it to work. Here is my code; can you help me?
I have a text file with this format:
#sometext
$configuration_TEstbk2_bk2_environment12 = 'lalala'
$configuration_TEstbk2_bk2_envoronment12 = 'lalala1'
$configuration_TEstbk2_bk2_staging12 = 'BACKUP 2'
$configuration_waq4faw4f_q4fq4qg4f = 'r234rq43rq4rqr'
$configuration_alice_StagingTEstBk_bk = 'testebk'
$configuration_deployment_overlays_alice_TEStStngDir = 'some'
$configuration_arefgqrqgrq_341q34tq34t = '134t135'
And I need to do something like:
sed s/$configuration_arefgqrqgrq_341q34tq34t ='134t135'/$configuration_arefgqrqgrq_341q34tq34t = 'NEWVALUE'/g
I have tried with many combinations with sed but I can't find one that works.

Would this work for you?
sed "/\$config_deployment_overlays_alice_arefgqrqgrq_341q34tq34t_staging/s/'134t135'/'NEWVALUE'/" file

I'd probably use:
sed '/$configuration_arefgqrqgrq_341q34tq34t *=/'"s/'134t135'/'NEWVALUE'/"
This uses a mix of single quotes and double quotes at the shell level to get the correct information to sed. The single quotes enclose the search condition for the lines containing $configuration_arefgqrqgrq_341q34tq34t followed by some blanks and an equals sign. This avoids the shell expanding what might be a shell variable name (but probably isn't, so the empty string would be substituted). I then switch to double quotes at the shell level, so that sed gets to see the single quotes: it substitutes the value in single quotes with the replacement value, but only on those lines that contain the given configuration parameter name.
I hope users never have to type those configuration parameter names.

I suppose your problem is with the quoting. You could use complex quoting to make sure everything is in single quotes, except the single quotes which need to be in double quotes:
sed 's/$configuration_arefgqrqgrq_341q34tq34t *= *'"'134t135'"'/$configuration_arefgqrqgrq_341q34tq34t = '"'NEWVALUE'/g"
... or you could use some temporary variables to make the whole thing more readable, and suitable for inclusion in a single pair of double quotes:
directive='$configuration_arefgqrqgrq_341q34tq34t'
oldvalue="'134t135'"
newvalue="'NEWVALUE'"
sed "s/$directive *= *$oldvalue/$directive = $newvalue/g"
(If you only expect one match, the /g flag is superfluous.)

You can also totally avoid matching quotes by capturing them:
sed '/$configuration_arefgqrqgrq_341q34tq34t/{
s/\(= *.\).*\(.\) *$/\1NEWVALUE\2/
}' input

This might work for you (GNU sed):
sed -r 's/^(\$\S+\s=\s'\'').*('\'')/\1NEWVALUE\2/' file

Related

What do I miss in this sed Expression?

I'd like to replace the database server of a horde config file from "localhost" to a remote server (I use "database.contoso.com" as a placeholder).
The file in question is /var/www/horde/config/conf.php.
The line in the file looks like this:
$conf['sql']['hostspec'] = 'localhost';
Now I have created a sed line like so:
sed s/\$conf\[\'sql\'\]\[\'hostspec\'\]\ \=\ \'localhost\'\;/\$conf\[\'sql\'\]\[\
'hostspec\'\]\ \=\ \'database\.contoso\.com\'\;/ /var/www/horde/config/conf.php
But for whatever reason, it does not work -I spare out the -i option for later.
While trying to figure out, why it does not work, I did this:
echo "\$conf['sql']['hostspec'] = 'localhost';"|sed s/\$conf\[\'sql\'\]\[\'hostspec\'\]\ \=\ \'localhost\'\;/\$conf\[\'sql\'\]\[\'hostspec\'\]\ \=\ \'database\.contoso\.com\'\;/
which returns this:
$conf['sql']['hostspec'] = 'localhost';
but it should return:
$conf['sql']['hostspec'] = 'database.contoso.com';
What am I missing?
From Escape a string for a sed replace pattern in this case it would work:
KEYWORD="\$conf['sql']['hostspec'] = 'localhost';"
REPLACE="\$conf['sql']['hostspec'] = 'database.contoso.com';"
ESCAPED_REPLACE=$(printf '%s\n' "$REPLACE" | sed -e 's/[\/&]/\\&/g')
ESCAPED_KEYWORD=$(printf '%s\n' "$KEYWORD" | sed -e 's/[]\/$*.^[]/\\&/g');
sed "s/$ESCAPED_KEYWORD/$ESCAPED_REPLACE/"
The immediate problem is that you are not quoting enough. To match a regex metacharacter literally, you need to pass in a literal backslash \\ followed by a literal, like for example \[. But the simplest solution by far is to use single quotes around your expression, and then only backslash the characters which are regex metacharacters.
Literal single quotes inside single quotes are still challenging. Here, I have chosen to end the single-quoted string, insert a backslash-escaped but otherwise unquoted single quote, and add an opening single quote to continue with another single-quoted string. The shell glues these together into a single string.
echo "\$conf['sql']['hostspec'] = 'localhost';" |
sed 's/\$conf\['\''sql'\''\]\['\''hostspec'\''\] = '\''localhost'\'';/$conf['\''sql'\'']['\''hostspec'\''] = '\''database.contoso.com'\'';/'
A better solution generally is to use backreferences to quote back part of the matched string so you don't have to repeat it.
echo "\$conf['sql']['hostspec'] = 'localhost';" |
sed 's/\(\$conf\['\''sql'\''\]\['\''hostspec'\''\] = '\''\)[^'\'']*'\'';/\1database.contoso.com'\'';/'
Demo: https://ideone.com/RA0MSi
A much much much better solution is to change your PHP script so that this setting can be overridden with an option, an environment variable, and/or a configuration file.
This might work for you (GNU sed & shell):
sed -E 's/(\$conf\[('\'')sql\2]\[\2hostspec\2\] = )\2localhost\2;/\1\2database.contoso.com\2;/' file
Use pattern matching to match and replace.
N.B. Certain metacharacters must be escaped/quoted i.e. $,[,] and then because the sed commands are surrounded by single quotes, each single quote (within the substitution command) must be replaced by '\'' (see here for reasoning). Also, back references can be used both in the RHS and the LHS of the substitution command. The back references in the LHS especially allow for the shortening of the overall command and perhaps make the regexp more readable.

sed not working as expected when trying to replace "user='mysql'" with "user=`whoami`"

The following command fails.
sed 's/user=\'mysql\'/user=`whoami`/g' input_file
An example input_file contains the following line
user='mysql'
The corresponding expected output is
user=`whoami`
(Yes, I literally want whoami between backticks, I don't want it to expand my userid.)
This should be what you need:
Using double quotes to enclose the sed command,
so that you are free to use single quotes in it;
escape backticks to avoid the expansion.
sed "s/user='mysql'/user=\`whoami\`/g" yourfile
I've intentionally omitted the -i option for the simple reason that it is not part of the issue.
To clarify the relation between single quotes and escaping, compare the following two commands
echo 'I didn\'t know'
echo 'I didn'\''t know'
The former will wait for further input as there's an open ', whereas the latter will work fine, as you are concatenating a single quoted string ('I didn'), an escaped single quote (\'), and another single quoted string ('t know').

Comment out one line of many files with sed

I need to comment out a line of many files on one path. The line reads
input_types = ['text']
and I need to replace it by
#input_types = ['text']
I want to do something like
sed -i 's/input_types/#input_types/g' path/to/files/*
but that would change all instances of input_types and I don't want that.
I also tried
sed -i 's/input_types = ['text']/#input_types = ['text']/g' path/to/files/*
but it didn't work
How can I change only that specific instance?
You last try was quite good, but two things have to be changed:
You use single quotes to enclose your expression, but single quotes are also part of the expression -- that gets confusing. In this case it's better to use double quotes for enclosing the expression, instead.
The [ ] brackets have to be escaped with backslashes: \[ \]
So, if you change the line to
sed -i "s/input_types = \['text'\]/#input_types = \['text'\]/g" /path/to/files/*
it should work.

sed match first word replace full line

I know this should be straight forward but I'm stuck, sorry.
I have two files both contain the same parameters but with different values. I'm trying to read one file line at a time, get the parameter name, use this to match in the second file and replace the whole line with that from file 1.
e.g. rw_2.core.fvbCore.Param.isEnable 1 (FVB_Params)
becomes
rw_2.core.fvbCore.Param.isEnable true (FVB_Boolean)
The lines are not always the same length but I always want to replace the whole line.
The code I have is as follows but it doesn't make the substitutions and I can't work out why not.
while read line; do
ParamName=`awk '{print $1}'`
sed -i 's/$ParamName.*/$line/g' FVB_Params.txt
done < FVB_Boolean.txt
You need your sed command within double quotes if you want those variables to be replaced with their values. You have single quotes, so sed is actually looking for strings with dollar signs to replace with the string '$line', not whatever your shell has in the $line variable.
In short, sed's not seeing the values you want. Switch to double quotes.

Sed delimiter options

In my code, I need to replace variable assignments with addresses:
sed -i "s/^variable = .*$/variable = http://myaddress/"
Obviously, this does not work because the forward slashes in the address are recognized in the sed command.
I want to keep the $ at the end of the first expression for replacing anything to the end of the line. I also do not want to escape the dollar sign as such, \$ because it will search for a dollar sign.
Also, I don't want to just escape the forward slashes in the address as there are also variables in some places for the addresses.
I've tried using # instead of / but have to include what I don't want to - the \$.
Are there any alternate delimiters I can use that fit my situation?
The $ is interpreted by your shell. Wrap the whole argument to sed with ' to prevent this.
sed -i 's#^variable = .*$#variable = http://myaddress#'
sed -i "s#^variable = .*$#variable = http://myaddress#" file
should work for you.
Note that the $ in the first expression is not literature "dollar", but a regex expression, means, the end of the line.
sed -i 's#^variable = .*#variable = http://myaddress#'