Sed to Replace & and slashes - sed

I have a data in below format.
new_name='abc &eft / def \ mno'
1.json
{
"text": {
"attribute": "old_name",
"data": "xyz"
}
}
I am trying to replace the value old_name by new_name.
My trail :--
sed "s/old_name/${new_name/&/\&}; s/old_name/${new_name////\/}/g" 1.json
I get below error :--
sed: -e expression #1, char 67: unknown option to `s'
Any guidance would be of great help.

You can skip the need to escape the slash by using a different delimiter for the substitution, but you still need to do one of the other replacements outside the sed command:
new_name='abc &eft / def \ mno'
quoted=${new_name/\\/\\\\\\\\}
sed "s=old_name=${quoted//&/\\&}=g" 1.json
But jq is far better tool to handle json:
new_name='abc &eft / def \ mno'
jq --arg n "$new_name" \
'.text.attribute |= (if . == "old_name" then $n else . end)' 1.json

Related

Parsing and accessing variables containing '$' in Makfile

I have gotten myself into Makefile-hell :(
I have a file test.par containing values:
$ABC=123 ! some comment
$DEF=456 ! comment
and I have a template source file (actually in fortran, but that does not make a difference here) test/template.c:
int main(void) {
return $ABC+$DEF ;
}
and I want to set the values in the code, like a preprocessor would do. So I wrote a target in my Makefile like so:
default:
for f in test/*; do \
while read l ; do \
key="$$(echo $$l | cut -d "=" -f 1 | tr -d ' ')";\
val=$$(echo $$l | cut -d "=" -f 2 | cut -d " " -f 1);\
[[ -z "$$val" ]] && \
val=$$(echo $$l | cut -d "=" -f 2 | cut -d " " -f 2);\
echo $$key $$val;\
cp $$f $$f.out ;\
sed -i "s/$$key/$$val/g" $$f.out;\
done < test.par;\
done;
I go through every file in test/ (there are many) in the for loop and "apply" every line in test.par in the while loop.
The expected result is
int main(void) {
return 123+456 ;
}
What I get is
int main(void) {
return $ABC+456 ;
}
And now it is getting crazy: If I switch the to lines in the test.par file, I get:
int main(void) {
return 123+$DEF ;
}
If there are more lines, there no substitution at all.
What is wrong with me!!!???!!!
edit: I cannot make too many changes to the original code, so aI was hoping to solve this in the Makefile.
You keep reusing the original file for substitutions, so only the last one actually sticks (the result of all substitutions but the last is overwritten by the next). After
sed "s/$$key/$$val/g" $$f > $$f.out;\
put
cp "$$f.out" "$$f";\
to fix this. (Or make a working copy of $$f, if you want $$f unchanged, e.g., cp "$$f" "$$f.out" before the loop and use sed -i "s/$$key/$$val/g" "$$f.out" inside.)

Colorize running log after marker

Often I need to analyze large logs in console.
I use the following command to colorize important keywords:
echo "string1\nerror\nsuccess\nstring2\nfail" | perl -p -e 's/(success)/\e[1;32;10m$&\e[0m/g;' -e 's/(error|fail)/\e[0;31;10m$&\e[0m/g'
It will colorize "success" with green, and error messages with red and keeps others lines unchanged (as they contain some useful info).
But in some cases I need to colorize values after some marker, but not marker itself, i.e. in these lines
Marker1: value1
Marker2: value2
need to highlight only value1 and value2 by known markers.
I'm looking for a way to modify my current oneliner to add this function
Also I tried the following solution, which I like less
#!/bin/bash
default=$(tput op)
red=$(tput setaf 1 || tput AF 1)
green=$(tput setaf 2 || tput AF 2)
sed -u -r "s/(Marker1: )(.+)$/\1${red}\2${default}/
s/(Marker2: )(.+)$/\1${green}\2${default}/" "${#}"`
But it has some problem with buffering, so it's ok for some constant file, but log which is continuosly running is not displayed at all
UPDATE:
Found a solution with help of some perl guru.
echo -e "string1\nerror\nsuccess\nstring2\nfail\nMaker1: value1\nMaker2: value2" | \
perl -p \
-e 's/(success)/\e[32m$&\e[0m/g;' \
-e 's/(error|fail)/\e[31m$&\e[0m/g;' \
-e 's/(Maker1:) (.*)/$1 \e[36m$2\e[0m/m;' \
-e 's/(Maker2:) (.*)/$1 \e[01;34m$2\e[0m/m;'
echo -e "string1\nerror\nsuccess\nstring2\nfail\nMaker1: value1\nMaker2: value2" | \
perl -p \
-e 's/(success)/\e[32m$&\e[0m/g;' \
-e 's/(error|fail)/\e[31m$&\e[0m/g;' \
-e 's/(Maker1:) (.*)/$1 \e[36m$2\e[0m/m;' \
-e 's/(Maker2:) (.*)/$1 \e[01;34m$2\e[0m/m;'
#!/bin/bash
default=$(tput op)
red=$(tput setaf 1 || tput AF 1)
green=$(tput setaf 2 || tput AF 2)
#default='e[0m'
#red='e[0;31;10m'
#green='e[1;32;10m'
# automaticaly use passed argument file if any or stdin if not
sed -u -r \
"/success/ s//${green}&${default}/
/error|fail/ s//${red}&${default}/
/^Marker1:/ {s//\1${red}/;s/$/${default}/;}
/^Marker2:/ {s//\1${green}/;s/$/${default}/;}" \
$( [ ${##} -gt 0 ] && echo ${#} )
For a one line:
remove other line thans sed one
replace newline in sed by ;
use directly the terminal code in place of variable
remove the last line if you pipe or use specific file instead

sed substitute with quotes and wildcard

I need to replace if ($_SESSION['POST']['*']==1){ with if (isset($_SESSION['POST']['*']) && $_SESSION['POST']['*']==1){
(I'm using * as a wild card)
I've tried sed -i "s/if ($_SESSION['POST']['.*']/if (isset($_SESSION['POST']['.*']) && $_SESSION['POST']['.*']/g" *.php and a few other variations without success.
Here goes...
sed "s/\(if (\)\(\$_SESSION\['POST']\['\([^']*\)']\)==1/\1isset(\2) \&\& \$_SESSION['POST']['\3']==1/" file
Using double quotes means that the $ symbols must be escaped, otherwise they will be interpreted as shell variables. The square brackets need to be escaped, otherwise they will be interpreted as the beginning of a range. It's OK to leave the closing square brackets as they are.
In order to capture the key, I have used a character class [^']*. This means zero or more characters that are not a single quote.
In the replacement, the captured groups (the parts between parentheses in the match) are referred to using \1, \2, etc.
Testing it out:
$ cat file
if ($_SESSION['POST']['foo']==1){
// do something
}
if ($_SESSION['POST']['bar']==1){
// do something else
}
$ sed "s/\(if (\)\(\$_SESSION\['POST']\['\([^']*\)']\)==1/\1isset(\2) \&\& \$_SESSION['POST']['\3']==1/" file
if (isset($_SESSION['POST']['foo']) && $_SESSION['POST']['foo']==1){
// do something
}
if (isset($_SESSION['POST']['bar']) && $_SESSION['POST']['bar']==1){
// do something else
}
By the way it makes the command a few characters shorter if you use extended regexp mode (-r or -E). In extended mode, the parentheses enclosing capture groups don't have to be escaped but literal ones do, so your command would then be:
sed -r "s/(if \()(\$_SESSION\['POST']\['([^']*)'])==1/\1isset(\2) \&\& \$_SESSION['POST']['\3']==1/" file
This sed should work:
s="if (\$_SESSION['POST']['name']==1){"
sed -r 's/(if +)\((([^=]+)[^\)]+)/\1(isset(\3) \&\& \2/' <<< "$s"
if (isset($_SESSION['POST']['name']) && $_SESSION['POST']['name']==1){
PS: Use sed -E instead of sed -r on OSX.
Here's another.
This is what we need to produce:
Pattern: if (\$_SESSION\['POST'\]\['\([^']*\)'\]
Replacement: if (isset($_SESSION['POST']['\1']) \&\& $_SESSION['POST']['\1']
When quoted in shell level:
Pattern: "if (\\\$_SESSION\['POST'\]\['\([^']*\)'\]"
Replacement: "if (isset(\$_SESSION['POST']['\1']) \\&\\& \$_SESSION['POST']['\1']"
Putting it together:
sed -i "s|if (\\\$_SESSION\['POST'\]\['\([^']*\)'\]|if (isset(\$_SESSION['POST']['\1']) \\&\\& \$_SESSION['POST']['\1']|g" file
Test:
# sed "s|if (\\\$_SESSION\['POST'\]\['\([^']*\)'\]|if (isset(\$_SESSION['POST']['\1']) \\&\\& \$_SESSION['POST']['\1']|g" <<'EOF'
> if ($_SESSION['POST']['ABC']==1){
> EOF
if (isset($_SESSION['POST']['ABC']) && $_SESSION['POST']['ABC']==1){

sed replace string except the matched string

Problem statement:
change every user agent that does not match A2PC or GENCOM with the user agent PROHIBITED and keep GENCOM and A2PC unchanged
Expression:
echo \"GENCOM\" | sed -r -e 's/(^((?!A2PC)(?!GENCOM).)*$)/PROHIBITED/g'
error:
sed: -e expression #1, char 41: Invalid preceding regular expression
I removed -r then error not thrown but its not working
echo \"GENDFGGH\" | sed -e 's/(^((?!A2PC)(?!GENCOM).)*$)/PROHIBITED/g'
"GENDFGGH"
Please help me for this solution
First look for your pattern and then do the sub:
# echo \"GENCsOM\" | sed -e '/^"\(GENCOM\|A2PC\)"$/! s/^.*$/PROHIBITED/'
PROHIBITED
# echo \"GENCOM\" | sed -e '/^"\(GENCOM\|A2PC\)"$/! s/^.*$/PROHIBITED/'
"GENCOM"
sed '/A2PC/ !{
/GENCOM/ ! {
s/$/PROHIBITED/
}
}' YourFile
double exclusion than a change, posix compliant

sed gives me ": unexpected EOF (pending }'s) error and I have no idea why

I'm trying to port a GNU sed command to BSD sed (in OSX). The command is:
cat -- "$1" | sed -n -e "\${/^#/H;x;/${tapPrintTapOutputSedPattern}/p;}" \
-e "/${tapPrintTapOutputSedPattern}/{x;/${tapPrintTapOutputSedPattern}/p;b;}" \
-e "/^#/{H;b;}" \
-e "x;/${tapPrintTapOutputSedPattern}/p" \
-e "/^Bail out!/q"
It works on GNU sed, but BSD sed gives this error:
sed: 2: "/^Bail out!/q
": unexpected EOF (pending }'s)
This is the command after the variable expansions, in case it's relevant:
cat -- "test021.tap" | sed -n \
-e "\${/^#/H;x;/^not ok\|^ok \([0-9]\+ \)\?# [tT][oO][dD][oO]\|^Bail out!/p;}" \
-e "/^not ok\|^ok \([0-9]\+ \)\?# [tT][oO][dD][oO]\|^Bail out!/{x;/^not ok\|^ok \([0-9]\+ \)\?# [tT][oO][dD][oO]\|^Bail out!/p;b;}" \
-e "/^#/{H;b;}" \
-e "x;/^not ok\|^ok \([0-9]\+ \)\?# [tT][oO][dD][oO]\|^Bail out!/p" \
-e "/^Bail out!/q"
Any ideas about why/how to fix it?
Cheers!
Try using newlines instead of a semicolons, at least before the branch commands (b) in the statements. See if this works:
sed -n "
\${
/^#/H
x
/${tapPrintTapOutputSedPattern}/p
}
/${tapPrintTapOutputSedPattern}/{
x
/${tapPrintTapOutputSedPattern}/p
b
}
/^#/{
H
b
}
x
/${tapPrintTapOutputSedPattern}/p
/^Bail out!/q
" "$1"