Reputation: 9364
I'm trying to delete a line with a the last character of the prior line with sed:
I have a json file :
{
"name":"John",
"age":"16",
"country":"Spain"
}
I would like to delete country of all entries, to do that I have to delete the comma for the json syntax of the prior line.
I'm using this pattern :
sed '/country/d' test.json
sed -n '/resolved//.$//{x;d;};1h;1!{x;p;};${x;p;}' test.json
Editor's note:
The OP later clarified the following additional requirements, which invalidated some of the existing answers:
- multiple occurrences of country
properties should be removed
- across all levels of the object hierarchy
- whitespace variations should be tolerated
Upvotes: 2
Views: 586
Reputation: 439597
Using a proper JSON parser such as jq
is generally the best choice (see below), but if installing a utility is not an option, try this GNU sed
command:
$ sed -zr 's/,\s*"country":[^\n]+//g' test.json
{
"name":"John",
"age":"16"
}
-z
splits the input into records by NUL
s, which, in this case means that the whole file is read at once, which enables cross-line substitutions.
-r
enables extended regular expressions for a more modern syntax with more features.
s/,\n"country":\s*//g
replaces all occurrences of a comma followed by a (possibly empty) run of whitespace (including possibly a newline) and then "country"
through the end of that line with the empty string, i.e., effectively removes the matched strings.
}
follows such a country
property on the same line.To demonstrate a more robust solution based on jq
.
Bertrand Martel's helpful answer contains a jq
solution, which, however, does not address the requirement (added later) of replacing country
attributes anywhere in the input object hierarchy.
In a not-yet-released version of jq
higher than v1.5.2
, a builtin walk/1
function will be available, which enables the following simple solution:
# Walk all nodes and remove a "country" property from any object.
jq 'walk(if type == "object" then del (.country) else . end)' test.json
In v1.5.2
and below, you can define a simplified variant of walk
yourself:
jq '
# Define recursive function walk_objects/1 that walks all objects in the
# hierarchy.
def walk_objects(f): . as $in |
if type == "object" then
reduce keys[] as $key
( {}; . + { ($key): ($in[$key] | walk_objects(f)) } ) | f
elif type == "array" then map( walk_objects(f) )
else . end;
# Walk all objects and remove a "country" property, if present.
walk_objects(del(.country))
' test.json
Upvotes: 2
Reputation: 58488
This might work for you (GNU sed):
sed 'N;s/,\s*\n\s*"country".*//;P;D' file
Read two lines into the pattern space and remove substitution string.
N.B. Allows for spaces either side of the line.
Upvotes: 2
Reputation: 47117
As pointed out before you should really consider using a JSON parser to parse JSON.
When that is said you can slurp the whole file, remove newlines and then replace accordantly:
$ sed ':a;N;$!ba;s/\n//g;s/,"country"[^}]*//' test.json
{"name":"John","age":"16"}
Breakdown:
:a; # Define label 'a'
N; # Append next line to pattern space
$!ba; # Goto 'a' unless it's the last line
s/\n//g; # Replace all newlines with nothing
s/,"country"[^}]*// # Replace ',"country...' with nothing
Upvotes: 2
Reputation: 45433
You can use a JSON parser like jq
to parse json file. The following will return the document without the country
field and write the new document in result.json
:
jq 'del(.country)' file.json > result.json
Upvotes: 1