sed single quotes - bash

I've been banging into escaping single quote's problem using SED (Bash shell).
I need to make
$cfg['Servers'][$i]['password'] = '';
into
$cfg['Servers'][$i]['password'] = 'mypassword';
What I've tried is:
sed -i "s/$cfg['Servers'][$i]['password'] = '';/$cfg['Servers'][$i]['password'] = '$rootpassword';/g" /usr/share/phpmyadmin/libraries/config.default.bak
Which ends up really jumbling the line.
$cfg['Servers'][$i]['password['Servers'][]['passsword'] = 'mypassword'
I've tried the '\'' to escape single quotes and I think everything else under the sun but just can't get it quite there.
can anyone point to my probable obvious mistake?
Thank you.

instead of escaping, you can use \x27 for single quote. this works not only for sed, for awk etc. as well.
see test:
kent$ cat tt
$cfg['Servers'][$i]['password'] = ''
kent$ sed -r 's/(\$cfg\[\x27Servers\x27\]\[\$i\]\[\x27password\x27\] \= \x27)\x27/\1mypassword\x27/g' tt
$cfg['Servers'][$i]['password'] = 'mypassword'
note that, the sed line may not be the best solution for your problem, e.g. put the whole string to "s/../" may not be necessary. However, I just want to show how the \x27 worked.

$ sed -i "s/\$cfg\['Servers'\]\[\$i\]\['password'\] = '';/\$cfg['Servers'][\$i]['password'] = '\$rootpassword';/g" file

Try this:
sed -i "/Servers.*password.*''$/s/''/'foo'/" /path/to/your/testfile
Match a line that contains "anything..Servers..anything..password..anything..''" (end with '') and on that line replace '' with 'foo'
This can match more than one lines, but only the first occurance will be changed.
Test it, it's most probable that .. Servers .. password .. '' is only on one line.
Or you can just escape everything.

Related

Replace the matched string in the comma separated string pattern

I have a comma separated strings inside brackets and I need to replace the string in matches the pattern.
And we have unknown string at the start and at the end. In the below example I need to replace c++ string with c if the row has string ruby.
I tried below sed command but it didnt work.
```
("java","php","ruby",".net","scala","c++",...n),
(".net","ruby","php","java","c++",...n),
("java",".net","ruby","php","c++",...n),
("ruby","java",".net","php","c++",...n);
```
```
sed -e "s/(\(.*\),\("ruby"\),\(.*\),"c++",\(.*\))/(\1,\2,\3,"c",\4)/g"
```
("java","php","ruby",".net","scala","c++",...n),
(".net","ruby","php","java","c++",...n),
("java",".net","ruby","php","c++",...n),
("ruby","java",".net","php","c++",...n);
'
{m,n,g}awk '/\42ruby\42/ ? NF = NF : NF' FS='"c[+][+]"' OFS='"c"'
'
("java","php","ruby",".net","scala","c",...n),
(".net","ruby","php","java","c",...n),
("java",".net","ruby","php","c",...n),
("ruby","java",".net","php","c",...n);
it seems like your sed command is not escaping double quotes
sed -e "s/(\(.*\),\("ruby"\),\(.*\),"c++",\(.*\))/(\1,\2,\3,"c",\4)/g"
change it to single quotes.
sed -e 's/(\(.*\),\("ruby"\),\(.*\),"c++",\(.*\))/(\1,\2,\3,"c",\4)/g' file.txt
or more simply use the below one...
sed -e 's/\("ruby"\),\(.*\),"c++"/\1,\2,"c"/g' my_file.txt
which will output
("jsjs","java",".net","php","c++",...n);
("java","php","ruby",".net","scala","c",...n),
(".net","ruby","php","java","c",...n),
("java",".net","ruby","php","c",...n),
("ruby","java",".net","php","c",...n);
("rubys","java",".net","php","c++",...n);

bash-replacing string in file, that contains special chars

as i said in the title im trying to replace a string in a file, that contains special characters , now the idea is to loop on every line of a "infofile" contains many lines of: whatiwantotreplace,replacer.
once I have this i want to do sed to a certain file to replace all the occurrences of string-> "whatiwantotreplace" with ->"replacer".
my code:
infofile="inforfilepath"
replacefile="replacefilepath"
while IFS= read -r line
do
what2replace="a" #$(echo "$line" | cut -d"," -f1);
replacer="b\\" #$(echo "$line" | cut -d"," -f2 );
sed -i -e "s/$what2replace/$replacer/g" "$replacefile"
#sed -i -e "s/'$what2replace'/'$replacer'/g" "$replacefile"
#sed -i -e "s#$what2replace#$replacer#g" "$replacefile"
#sed -i -e s/$what2replace/$replacer/g' "$replacefile"
#sed -i -e "s/${what2replace}/${replacer}/g" "$replacefile"
#${replacefile//what2replace/replacer}
done < "$infofile"
As you can see, the string that want to replace and the string that i want to replace with,may contain special characters , all the commented lines are the things I tried (things I saw online) but still clueless.
for some i got this error:
"sed: -e expression #1, char 8: unterminated `s' command"
and for some just nothing happend.
really need your help
Edit: inputs and outputs:
It's hard to give inputs and output, because all of the variations I tried had the same thing , didn't changed anything, the only one gave the above error is the variation with #.
thanks for your effort.
You're barking up the wrong tree - you're trying to do literal string replacements using a tool, sed, that doesn't have functionality to handle literal strings. See Is it possible to escape regex metacharacters reliably with sed for the convoluted mess required to try to force sed to do what you want and also https://unix.stackexchange.com/q/169716/133219 for why to avoid shell loops for manipulating text.
Just use awk instead since it has literal string functions and loops implicitly itself:
awk '
NR==FNR{map[$1]=$2; next}
{
for (old in map) {
new = map[old]
head = ""
tail = $0
while ( s = index(tail,old) ) {
head = head substr(tail,1,s-1) new
tail = substr(tail,s+length(old))
}
$0 = head tail
}
}
' "$infofile" "$replacefile"
The above is untested of course since you didn't provide any sample input/output.
You can try this way
what='a';to='b\\\\';echo 'sdev adfc xdae' | sed "s/${what}/${to}/g"
output
sdev b\\dfc xdb\\e

Sed fails to update long text

Consider test file csf.conf:
CC_DENY = ""
Running the command:
sed -i -E 's/(CC_DENY *= *")[^"]+/\1AR,BE,CL,CN,CO,CS,ES,FR,GR,HK,IT,KO,PA,PE,PH,PL,RS,RU,SG,SK,TH,UA,VN,AE,AF,AL,AS,AZ,BA,BD,BF,BH,BJ,BN,CI,DJ,EG,EH,ER,ET,GM,GN,GW,IQ,IR,IS,JO,KG,KM,KW,KZ,LB,LY,MC,MK,ML,MR,MV,MY,NE,NG,OM,PK,PS,QA,SA,SD,SL,SN,SO,SY,TD,TJ,TM,TN,TR,UZ,XK,YE,YT/g' csf.conf
Does not replace the match inside the file. Output should look like this:
CC_DENY="AR,BE,CL,CN,CO,CS,ES,FR,GR,HK,IT,KO,PA,PE,PH,PL,RS,RU,SG,SK,TH,UA,VN,AE,AF,AL..."
Sed v4.2.2, same result on Debian 8, and Centos 7
This has nothing to do with long text, your regexp just doesn't match the content of your file. Change [^"]+ to [^"]* so it'll match even when there's nothing between the double quotes "". Look:
$ cat csf.conf
CC_DENY = ""
$ sed -E 's/(CC_DENY *= *")[^"]+/\1foo/' csf.conf
CC_DENY = ""
$ sed -E 's/(CC_DENY *= *")[^"]*/\1foo/' csf.conf
CC_DENY = "foo"
wrt the comment below from the OP that this sed command works:
$ cat file
LF_SPI = ""
$ sed -E 's/(LF_SPI *= *\")[^\"]+/\1blah/g' file
LF_SPI = ""
Clearly and predictably, no it does not. It simply can't because the regexp metacharacter + means 1 or more so [^\"]+ states there must be at least one non-" after the " and that just does not exist in the input file. There is no reason to escape the double quotes btw.
Suppose the current variable value in the file is empty. Then your regular expression doesn't match because [^"]+ means "any character, except double quote repeated one or more times".
You might fix it by replacing + quantifier with * (zero or more times). But suppose the value contains a double quote:
CC_DENY = "\""
Then the [^"]* will match everything until it gets to the double quote within the value.
Thus, I suggest the following command:
# Put the variable value here
value='AR,BE\\" ... YE,YT';
sed -i -r 's/^( *CC_DENY *= *").*"/\1'"$value"'"/' csf.conf
Also note, that the expression above uses an anchor for the beginning of the line. Otherwise, it will fail to match as expected, if such a CC_DENY = "... exists in the variable value in the configuration file: CC_DENY = "SOMETHING_CC_DENY = \"value\"".
Sed is certainly the wrong tool for this:
#!/usr/bin/awk -f
BEGIN {
FS = OFS = "\42"
}
$2 = "AR,BE,CL,CN,CO,CS,ES,FR,GR,HK,IT,KO,PA,PE,PH,PL,RS,RU,SG,SK,TH,UA,VN," \
"AE,AF,AL,AS,AZ,BA,BD,BF,BH,BJ,BN,CI,DJ,EG,EH,ER,ET,GM,GN,GW,IQ,IR,IS,JO,KG," \
"KM,KW,KZ,LB,LY,MC,MK,ML,MR,MV,MY,NE,NG,OM,PK,PS,QA,SA,SD,SL,SN,SO,SY,TD,TJ," \
"TM,TN,TR,UZ,XK,YE,YT"

Add a line after an occurrence

The variables are
espejo=u456789
usuario=u123456
grupo=unixgr
I want to add after the line occurrence of variable $espejo, the text in variables $usuario and $grupo:
cp $DIRECTORY/usu.txt $DIRECTORY/usu.txt.`date '+%F'`
sed "/${espejo}/a\ ${usuario} ${grupo}" $DIRECTORY/usu.txt.`date '+%F'` > $DIRECTORY/usu.txt
I got this error during the execution:
sed: 0602-404 Function /u456789/a\u123456 unixgr cannot be parsed.
I don't know what is wrong.
Try the following:
sed "/${espejo}/a\
${usuario} ${grupo}" $DIRECTORIO/usu.txt.`date '+%F'` > $DIRECTORIO/usu.txt
Note that after the backslash on first line there is no any other symbols except new line.
Try this:
sed "s:${espejo}:${espejo}\n${usuario} ${grupo}:" $DIRECTORIO/usu.txt.`date '+%F'` > $DIRECTORIO/usu.txt
If the above just adds n instead of newline, try this:
sed "s:${espejo}:${espejo}\
${usuario} ${grupo}:" $DIRECTORIO/usu.txt.`date '+%F'` > $DIRECTORIO/usu.txt
This will append the new variable in new line. I guess you are facing the problem since ${espejo} contains / character in it.
This might work for you (GNU sed):
sed "/$espejo/r /dev/stdin" file <<<" ${usuario} ${grupo}"

Escape UNIX character

This should be easy but i just can't get out of it:
I need to replace a piece of text in a .php file using the unix command-line.
using: sudo sed -i '' 's/STRING/REPLACEMENT/g' /file.php (The quotes after -i are needed because it runs on Mac Os X)
The string: ['password'] = ""; needs to be replaced by: ['password'] = "$PASS";
$PASS is a variable, so it gets filled in.
I got up to something like:
sudo sed -i '' 's/[\'password\'] = ""\;/[\'password\'] = "$PASS"\;/g' /file.php
But as i'm new with UNIX i don't know what to escape...
What should be changed? Thanks!
Unfortunately sed cannot robustly handle variables that might contain various characters that are "special" to sed and shell. You need to use awk for this, e.g. with GNU awk for gensub():
gawk -v pass="$PASS" '{$0=gensub(/(\[\047password\047] = \")/,"\\1"pass,"g")}1' file
See how sed fails below when PASS contains a forward slash but awk doesn't care:
$ cat file
The string: ['password'] = ""; needs to be replaced
$ PASS='foo'
$ awk -v pass="$PASS" '{$0=gensub(/(\[\047password\047] = \")/,"\\1"pass,"g")}1' file
The string: ['password'] = "foo"; needs to be replaced
$ sed "s/\(\['password'\] = \"\)\(\";\)/\1$PASS\2/g" file
The string: ['password'] = "foo"; needs to be replaced
$ PASS='foo/bar'
$ awk -v pass="$PASS" '{$0=gensub(/(\[\047password\047] = \")/,"\\1"pass,"g")}1' file
The string: ['password'] = "foo/bar"; needs to be replaced
$ sed "s/\(\['password'\] = \"\)\(\";\)/\1$PASS\2/g" file
sed: -e expression #1, char 38: unknown option to `s'
You need to use \047 or some other method (e.g. '"'"' if you prefer) to represent a single quote within an awk script that's single-quote-delimitted.
In awks without gensub() you just use gsub() instead:
awk -v pass="$PASS" '{pre="\\[\047password\047] = \""; gsub(pre,pre pass)}1' file
if you want to expand variable in sed, you have to use double quote, so something like
sed -i... "s/.../.../g" file
that is, you don't have to escape those single quotes, also you could use group reference to save some typing. you could try:
sudo sed -i '' "s/\(\['password'\] = \"\)\(\";\)/\1$PASS\2/g" /file.php

Resources