In a bash script, I wish to get some numbers from the output of a command and store them in variables. An example of the command output:

25 results [22 valid, 2 invalid, 1 undefined]

I would like to save the four numbers in the previous command-output as variables called results, valid, invalid, undefined.

  • No, only spaces in between as shown.
    – nabeelj
    Sep 12, 2018 at 15:06
  • please try below and let me know so I can tweak it if it did not work for you!
    – user88036
    Sep 12, 2018 at 15:07

5 Answers 5


Since you want to store multiple separate values, I assume that you want to store them in an array:

$ str='25 results [22 valid, 2 invalid, 1 undefined]'

$ readarray -t arr < <( grep -E -o '[0-9]+' <<<"$str" )

This reads the output of grep into an array called arr. The grep command will output each separate number found in $str on its own line by matching the extended regular expression [0-9]+ against the string and extracting each match. grep reads the string from a "here-string", and readarray reads the grep result using a process substitution.

The values may then be used as

$ printf 'value: %s\n' "${arr[@]}"
value: 25
value: 22
value: 2
value: 1

or, to look at individual values, use e.g. "${arr[0]}", "${arr[1]}", etc. The array contains "${#arr}" values.


To read directly from a command:

readarray -t arr < <( mycommand | grep -E -o '[0-9]+' )
  • Thanks, Is there any alternative to the command readarray . I don't have this command in my system! is readarray equivalent to read. Thanks!
    – user88036
    Sep 12, 2018 at 16:01
  • 1
    @Goro Your bash is older than release 4.0 (2009)?
    – Kusalananda
    Sep 12, 2018 at 16:51
  • @ Kusalananda. Thanks for the response. No it is 4.2.46(2)-release
    – user88036
    Sep 12, 2018 at 16:54
  • 1
    @Goro In that case, I see no reason why readarray would not be a valid command, unless you are in fact running some other shell that is not bash.
    – Kusalananda
    Sep 12, 2018 at 17:04
  • 1
    @Goro Ah, just managed to find that the -t option to readarray was added in bash 4.3. It strips the delimiter (newlines by default) off from the read data. Without -t, each array element would have a trailing newline.
    – Kusalananda
    Sep 12, 2018 at 17:06

Let's say that the output of this command is saved in a file called output.txt, then you can use the commands awk and grep as follows:

results=$(grep results output.txt | awk '{print $1}')    
valid=$(grep valid output.txt | awk '{print $3}' | tr -d [])
invalid=$(grep invalid output.txt | awk '{print $5}' | tr -d [])
undefined=$(grep undefinedoutput.txt | awk '{print $7}' | tr -d [])

Include these four lines in your bash where it fits.

Instead, you can only use awk to find a matching pattern, as follows:

results=$(awk '/results/{ print $1 }' output.txt)
valid=(awk '/valid/{ print $3 }' output.txt | tr -d [])
invalid=(awk '/invalid/{ print $5 }' output.txt | tr -d [])
undefined=(awk '/undefined/{ print $7 }' output.txt | tr -d [])
  • 2
    With the exception of your minor typo ($1 in the second line should be $3}, this works!
    – nabeelj
    Sep 12, 2018 at 15:14
  • The grep seems unnecessary, right? Since the output is already a single line.
    – nabeelj
    Sep 12, 2018 at 15:15
  • 1
    @nabeelj grep + awk almost always means the grep is unnecessary anyway since awk can do pattern matching itsel Sep 12, 2018 at 15:46
  • The grep may be too permissive if any of those words appear elsewhere in the output. Sep 12, 2018 at 19:14

Assuming your output is in a variable called output, you can split it with sed, keeping just the spaces and digits, to allow you easily split the "words" into an array:

tim@host:~$ res=($(sed 's/[^0-9 ]*//g' <<< $output))
tim@host:~$ printf "results: %s\nvalid: %s\ninvalid: %s\nundefined: %s\n" "${res[@]}"
results: 25
valid: 22
invalid: 2
undefined: 1
  • 1
    Don't put variable expansions into the printf format string. Use placeholders like printf 'results: %s\nvalid: %s\n ...etc..' "${res[@]}"
    – Kusalananda
    Sep 12, 2018 at 15:48
  • is that to protect against variables that contain characters that printf would interpret? Sep 12, 2018 at 20:21

You could use parameter expansion to replace everything that's not a digit with a space, then use word splitting to read the result into your variables:

str='25 results [22 valid, 2 invalid, 1 undefined]'
read results valid invalid undefined <<< ${str//[![:digit:]]/ }

The expansion results in something like

$ echo "${str//[![:digit:]]/ }"
25          22        2          1

and read does the rest.


On any POSIX shell:

a='aja 25 results [22 valid, 2 invalid, 1 undefined]'

set --                         # clean the list of argumnets.
while [ ${#a} -gt 0 ]; do      # while a is not empty, loop.
    b=${a%%[0-9]*}             # extract leading characters that are not digits (if any).
    a=${a#"$b"}                # remove those from the source variable.
    b=${a%%[^0-9]*}            # extract the leading digits.
    set -- "$@" ${a:+"$b"}     # until a empty, add numbers to the list.
    a=${a#"$b"}                # remove the digits from the source string.

printf '<%s> ' "$@"; echo      # print the list of values.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.