I am using Ubuntu and I want to extract the values between two patterns and the required string is not in the file.

My data is as shown below:


I want to get the text between , and ], and that means I want 11111-222-33333-444444. How can I do this using sed?

  1. Ubuntu is the operating system I'm using.
  2. It was not stored in any file or variable. It was the output of one command. I want to pipe the output of command1 to sed and parse the above string to get only the required information.
  3. It was in JSON format. This was the only data we would be getting...

4 Answers 4


Using jq (which does not care whether the input is in compact or multi-line form):

your-command | jq -r '.[0].rows[0]._uuid[1]'

Your JSON document is an array consisting of objects and you want the first of these top-level objects, .[0]. That object contains a rows array, and you want the first of its elements, .rows[0]. That element has another array called _uuid, and you want that array's second element, ._uuid[1].

With -r you get the decoded, "raw", data back. Without -r, you get a (quoted) JSON string.

A totally different way of getting the data from this particular JSON document would be to get the last value in the document:

your-command | jq -r 'getpath([paths(scalars)][-1])'

This first generates all "paths" for each scalar value in the whole document with paths, and picks out the last of them. The expression then uses this path-of-the-last-scalar with getpath to pull out the last value. For the given document, this results in the expected output.

The following is probably doing the same thing, but with explicit recursion using .. and with select() to pull out all scalar values:

your-command | jq -r '[.. | select(scalars)][-1]'

Personally, I would go with the topmost suggestion in this answer, as it uses the structure of the document, which is bound to be meaningful to the user in some way. That code would have to be revisited, and the question reformulated, if any of the involved arrays starts containing more elements.


If we can be certain that there is always only one , per line, and you want everything between that , and the first ] that comes after it, you can use sed:

 $ echo '[{"rows":[{"_uuid":["uuid","11111-222-33333-4444444"]}]}]' | sed 's/.*,\([^]]*\)\].*/\1/'

or, to also avoid the quotes:

   $ echo '[{"rows":[{"_uuid":["uuid","11111-222-33333-4444444"]}]}]' | sed 's/.*,"\([^]]*\)"\].*/\1/'

However, since this looks like JSON data, you should not use sed as this solution will break with even the smallest change in the input format. You should use a dedicated JSON parser like jq instead.

  • 1
    how can we use jq for the same problem statement Dec 6, 2021 at 13:14
  • @KattaSivasai I don't know jq well enough to answer, sorry. As for the ' yes, you could remove it in this specific case, but don't: it is a good habit to always quote anything you pass to echo so that it is protected from the shell.
    – terdon
    Dec 6, 2021 at 13:16
  • thanks @terdon for your valuable answers. Dec 6, 2021 at 13:17
  • @KattaSivasai In some shells, depending on the shell's settings, an unquoted globbing pattern (which is what [...] would be interpreted as) would cause an error if the pattern does not match anything. This is the default in the zsh shell and would be the case in bash if the shell's failglob shell option was set. With nullglob set in bash, the string would disappear entirely if it does not match any filenames.
    – Kusalananda
    Dec 6, 2021 at 14:53
  • @they actually and intriguingly enough, with bash, echo [{...}] | jq (using the OP's string) fails with parse error: Invalid numeric literal at line 1, column 7 but echo '[{..}]' | jq works fine. Presumably because echo foo"bar"baz results in foobarbaz, so the double quotes are being removed.
    – terdon
    Dec 6, 2021 at 14:57

If your valuable data contains just numbers and -, you can use this. (If uuid longer than 23, no problem.)

echo '[{"rows":[{"_uuid":["uuid","11111-222-33333-4444444"]}]}]' | sed  -n "s/.*,\"\([0-9-]\{23,\}\)\"].*/\1/p"

Output : 11111-222-33333-4444444

  • Thanks for all your quick responces, it's very helful Dec 6, 2021 at 13:12

Using Raku (formerly known as Perl_6)

~$ raku -MJSON::Tiny -e 'from-json($_)[0].<rows>[0].<_uuid>[1].put given slurp();'  file

Above is an answer coded in Raku, a member of the Perl-family of programming languages. Regarding command-line flags, calling raku --help at the shell command line tells us:

  • The -e flag executes the (following) 'one-liner' program, with strict enabled by default.

  • The -M flag loads a module prior to running the 'one-liner' program, in this case the JSON::Tiny module.

Sample Input:


Sample Output:


According to the module home pages (first and second links below), "JSON::Tiny implements RFC7159, which is a superset of ECMA-404, in that it permits any value as a top-level JSON string, not just arrays and objects." The OP's input can be round-tripped using from-json and to-json module functions.

Please note this Raku answer, specifically the [0].<rows>[0].<_uuid>[1] descent into the JSON structure, bears striking similarity to the excellent first jq answer posted by @Kusalananda.


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .