Reputation: 17326
Linux RH 5.11
GNU sed
version 4.1.5
I have the following file where I want to replace the value of +
with another (version) value for all lines where the KEY value starts with either ABC, DEF or XYZ by running one command (using sed
group words capability while doing word wrap/regex based matches).
linux_user@linux_server123 [ ~ ] 18:37:18 :9152> cp ~/my-file.json ~/BKUP-my-file.json; cat ~/my-file.json
{
"versions": {
"ABC_PROJECT_Product": "+",
"IGNORE1_PROJECT_Product": "1.8.0.1371",
"DEF_PROJECT_Product": "+",
"XYZ_PROJECT_Product": "+",
"IGNORE2_PROJECT_Product": "1.1.0.830",
"ABC_PROJECTGlobal": "+",
"DEF_PROJECTGlobal": "+",
"IGNORE2_PROJECTGlobal": "1.1.0.830",
"ABC_PROJECTGlobalSSD": "+",
"DEF_PROJECTGlobalSSD": "+",
"ABC_PROJECT_ProductSSD": "+",
"IGNORE3_PROJECT_ProductSSD": "1.0.0.4913",
"DEF_PROJECT_ProductSSD": "+",
"ABC_PROJECTLocalREBS": "+",
"IGNORE4_PROJECTLocalREBS": "1.1.0.865",
"ABC_PROJECT_ProductODNS": "+",
"IGNORE3_PROJECT_ProductODNS": "1.0.0.4913",
"DEF_PROJECT_ProductODNS": "+",
"ABC_PROJECT_ProductIDNS": "+",
"DEF_PROJECT_ProductIDNS": "+",
"IGNORE2_PROJECT_ProductIDNSS": "1.1.0.830",
"ABC_PROJECTGlobalIDNS": "+",
"DEF_PROJECTGlobalIDNS": "+",
"ABC_PROJECTGlobalODNS": "+",
"DEF_PROJECTGlobalODNS": "+",
"ABC_PROJECTLocalSpecial": "+",
"IGNORE4_PROJECTLocalSpecial": "1.1.0.865",
"ABC_PROJECT_ProductSpecial": "+",
"IGNORE5_PROJECT_ProductSpecial": "2.1.0.683",
"DEF_PROJECT_ProductSpecial": "+",
"ABC_PROJECTGlobalSpecial": "+"
}
}
.
cp ~/BKUP-my-file.json ~/my-file.json;
sed_regex="\(ABC\|DEF\|XYZ\)";
sed -i "s/\(.*\"${sed_regex}_PROJECT.*\".*:.*\"\).*\(\".*\)/\11.22.333.4444\2/" ~/my-file.json;
sed -n "/.*\(ABC\|DEF\|XYZ\)_PROJECT.*/p" ~/my-file.json
"ABC_PROJECT_Product": "1.22.333.4444ABC
"DEF_PROJECT_Product": "1.22.333.4444DEF
"XYZ_PROJECT_Product": "1.22.333.4444XYZ
"ABC_PROJECTGlobal": "1.22.333.4444ABC
"DEF_PROJECTGlobal": "1.22.333.4444DEF
"ABC_PROJECTGlobalSSD": "1.22.333.4444ABC
"DEF_PROJECTGlobalSSD": "1.22.333.4444DEF
"ABC_PROJECT_ProductSSD": "1.22.333.4444ABC
"DEF_PROJECT_ProductSSD": "1.22.333.4444DEF
"ABC_PROJECTLocalREBS": "1.22.333.4444ABC
"ABC_PROJECT_ProductODNS": "1.22.333.4444ABC
"DEF_PROJECT_ProductODNS": "1.22.333.4444DEF
"ABC_PROJECT_ProductIDNS": "1.22.333.4444ABC
"DEF_PROJECT_ProductIDNS": "1.22.333.4444DEF
"ABC_PROJECTGlobalIDNS": "1.22.333.4444ABC
"DEF_PROJECTGlobalIDNS": "1.22.333.4444DEF
"ABC_PROJECTGlobalODNS": "1.22.333.4444ABC
"DEF_PROJECTGlobalODNS": "1.22.333.4444DEF
"ABC_PROJECTLocalSpecial": "1.22.333.4444ABC
"ABC_PROJECT_ProductSpecial": "1.22.333.4444ABC
"DEF_PROJECT_ProductSpecial": "1.22.333.4444DEF
"ABC_PROJECTGlobalSpecial": "1.22.333.4444ABC
Question 1:
Why sed
is putting ABC
or DEF
or XYZ
in place of the actual \2
value, which I understand should be either: ",
or just: "
i.e. line entry in JSON object (with/without any space/tabs) in that line?
Question 2:
How can I get "ABC_PROJECT_Product": "+",
value as:
"ABC_PROJECT_Product": "1.22.333.4444",
Question 3:
Any why the heck using this sed
fixes question 1 & 2 both (apart from making it faster duh).
sed -i "/.*\"${sed_regex}_PROJECT.*\"/ s/\(.*\".*\".*:.*\"\).*\(\".*\)/\11.22.333.4444\2/" ~/my-file.json;
May be awk
can do this easily?
Upvotes: 0
Views: 290
Reputation: 203324
@cdub answered your 3 questions but is this what you're trying to do?
$ sed -E '/"(ABC|DEF|GHI)_PROJECT/ s/[+]/11.22.333.4444/' file
{
"versions": {
"ABC_PROJECT_Product": "11.22.333.4444",
"IGNORE1_PROJECT_Product": "1.8.0.1371",
"DEF_PROJECT_Product": "11.22.333.4444",
"XYZ_PROJECT_Product": "+",
"IGNORE2_PROJECT_Product": "1.1.0.830",
"ABC_PROJECTGlobal": "11.22.333.4444",
"DEF_PROJECTGlobal": "11.22.333.4444",
"IGNORE2_PROJECTGlobal": "1.1.0.830",
"ABC_PROJECTGlobalSSD": "11.22.333.4444",
"DEF_PROJECTGlobalSSD": "11.22.333.4444",
"ABC_PROJECT_ProductSSD": "11.22.333.4444",
"IGNORE3_PROJECT_ProductSSD": "1.0.0.4913",
"DEF_PROJECT_ProductSSD": "11.22.333.4444",
"ABC_PROJECTLocalREBS": "11.22.333.4444",
"IGNORE4_PROJECTLocalREBS": "1.1.0.865",
"ABC_PROJECT_ProductODNS": "11.22.333.4444",
"IGNORE3_PROJECT_ProductODNS": "1.0.0.4913",
"DEF_PROJECT_ProductODNS": "11.22.333.4444",
"ABC_PROJECT_ProductIDNS": "11.22.333.4444",
"DEF_PROJECT_ProductIDNS": "11.22.333.4444",
"IGNORE2_PROJECT_ProductIDNSS": "1.1.0.830",
"ABC_PROJECTGlobalIDNS": "11.22.333.4444",
"DEF_PROJECTGlobalIDNS": "11.22.333.4444",
"ABC_PROJECTGlobalODNS": "11.22.333.4444",
"DEF_PROJECTGlobalODNS": "11.22.333.4444",
"ABC_PROJECTLocalSpecial": "11.22.333.4444",
"IGNORE4_PROJECTLocalSpecial": "1.1.0.865",
"ABC_PROJECT_ProductSpecial": "11.22.333.4444",
"IGNORE5_PROJECT_ProductSpecial": "2.1.0.683",
"DEF_PROJECT_ProductSpecial": "11.22.333.4444",
"ABC_PROJECTGlobalSpecial": "11.22.333.4444"
}
}
The above requires GNU (or OSX/BSD) sed as you're already using for -E
. Alternatively this will work with any awk in any shell on every UNIX box:
awk '/"(ABC|DEF|XYZ)_PROJECT/{sub(/[+]/,"11.22.333.4444")} 1' file
Upvotes: 1
Reputation: 2297
Question #1:
The sed string has a nested grouping, so \2
refers to \(ABC\|DEF\|XYZ\)
. That's why we see ABC, DEF, etc. at the end of each line. We can more clearly see the nesting by re-writing the sed string with the sed_regex variable substituted:
sed "s/\(.*\"\(ABC\|DEF\|XYZ\)_PROJECT.*\".*:.*\"\).*\(\".*\)/\11.22.333.4444\2/"
Question#2:
Something like this could work:
sed_regex="\(ABC\|DEF\|XYZ\)"; sed "s/$sed_regex\(_PROJECT.*\)\("+"\)/\1\211.22.333.4444/g"
Question #3:
The revised sed string in the OP doesn't use a nested grouping and the regex appears to properly match the pattern.
Upvotes: 1