DaveA
DaveA

Reputation: 23

Extract first instance of value for specific key with sed

From this string (sanitized), I'm trying to extract the first instance of the "id" from this payload (formatted here, but is actually all on one line):

{
    "result": [{
        "id": "a4e2a4682e286dea803aaa4d2aff851212c3",
        "name": "test.com",
        "status": "active",
        "paused": false,
        "type": "partial",
        "development_mode": 0,
        "verification_key": "12312312-123123",
        "original_name_servers": ["dns1.test.com", "dns2.test.com"],
        "original_registrar": null,
        "original_dnshost": "register",
        "modified_on": "2017-02-24T17:59:59.080278Z",
        "created_on": "2017-01-31T20:27:03.395683Z",
        "meta": {
            "step": 4,
            "wildcard_proxiable": false,
            "custom_certificate_quota": 0,
            "page_rule_quota": 3,
            "phishing_detected": false,
            "multiple_railguns_allowed": false
        },
        "owner": {
            "type": "organization",
            "id": "12312123123",
            "name": "Test"
        },
        "permissions": ["#analytics:read", "#billing:edit", "#billing:read", "#cache_purge:edit", "#dns_records:edit", "#dns_records:read", "#lb:edit", "#lb:read", "#logs:read", "#organization:edit", "#organization:read", "#ssl:edit", "#ssl:read", "#waf:edit", "#waf:read", "#zone:edit", "#zone:read", "#zone_settings:edit", "#zone_settings:read"],
        "plan": {
            "id": "0feeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
            "name": "Free Website ",
            "price ": 0,
            "currency ": "USD ",
            "frequency ": "",
            "is_subscribed ": true,
            "can_subscribe ": false,
            "legacy_id ": "free ",
            "legacy_discount ": false,
            "externally_managed ": false
        }
    }],
    "result_info": {
        "page": 1,
        "per_page ": 20,
        "total_pages": 1,
        "count ": 1,
        "total_count ": 1
    },
    "success ": true,
    "errors ": [],
    "messages ": []
}

using following sed statement:

`echo $txtauthkey | sed -e 's/^.*"id"[ ]*:[ ]*"//' -e 's/".*//'`

but it extracts the last instance of "id", ie "0feeeeeeeeeeeeeeeeeeeeeeeeeeeeee"

Upvotes: 1

Views: 81

Answers (2)

Benjamin W.
Benjamin W.

Reputation: 52506

If you have access to it, this is very simple with the JSON parser jq:

$ jq -r '.result[0].id' infile.json
a4e2a4682e286dea803aaa4d2aff851212c3

With sed, you could reverse the input and extract the last instance of "value":"di" and reverse it again:

$ rev infile.json | sed 's/.*"\([^"]*\)"[[:blank:]]*:[[:blank:]]*"di".*/\1/' | rev
a4e2a4682e286dea803aaa4d2aff851212c3

And with sed and nothing else, I can't think of anything better than shaving of characters from the beginning of the string until it starts with "id":

$ sed ':a;/^id"/{s/id"[[:blank:]]*:[[:blank:]]*"\([^"]*\).*/\1/;q};s/[^"]*"//;ba' infile.json
a4e2a4682e286dea803aaa4d2aff851212c3

More readable:

:a          # Label to branch to
/^id"/ {    # If the line starts with id"
    # Extract value of "id" key
    s/id"[[:blank:]]*:[[:blank:]]*"\([^"]*\).*/\1/
    q       # Quit - we are done
}
s/[^"]*"//  # Remove characters up and including next double quote
ba          # Branch to label

Upvotes: 0

Bohemian
Bohemian

Reputation: 425358

Use a reluctant quantifier .*? rather than a greedy one .*. Unfortunately, no flavour of sed supports reluctant quantifier, but perl does:

`echo $txtauthkey | perl -pe 's/^.*?"id" *: *"//;s/".*//'
  • .* consumes as much as possible - all the way to the last '"id"
  • .*? consumes as little as possible - which will stop at the first `'"id"'

Upvotes: 1

Related Questions