32

I have a string "rtcpOnNbActive true" stored in a variable x. I want to extract "true" as substring and store in a variable. How can I do this?

1
  • Will there always be a space in x just before the substring you want to extract?
    – PM 2Ring
    Dec 13, 2014 at 8:19

7 Answers 7

42

Try this way:

y=$(echo $x | awk '{print $2}')
echo $y
  • echo $x display the value of x.
  • awk '{print $2}' prints the second field of the previously displayed x.
  • $(...) hold the output and let assign it to y.
2
  • 3
    echo $x is not display the value of x. printf '%s\n' "$x" would be. Dec 13, 2014 at 9:14
  • 4
    awk '{print $2}' prints the second field of each line of the previously displayed x. Dec 13, 2014 at 9:15
12

Assuming that there's at least one space before the substring you wish to extract (and that the substring does not contain any spaces), you can do this with a simple parameter expansion:

x="rtcpOnNbActive     true"
y="${x##* }"
echo "[$y]"

output

[true]
2
  • 4
    echo is not portable for anything other than a literal string that doesn't start with - and doesn't contain any escape sequences. Its behavior varies even for the bash builtin, depending on how it was compiled, and whether XPG_ECHO is set. Assuming the string contains no escape sequences, this should be fine, but printf '[%s]\n' "$y" is still better.
    – alexia
    Dec 13, 2014 at 12:59
  • 1
    @nyuszika7h: Good point, and after having read Stéphane Chazelas say similar things here and in other recent questions I really ought to break my habit of using echo to display the value of variables, even in "throw-away" examples like this.
    – PM 2Ring
    Dec 14, 2014 at 8:00
10

It's possible to use bash arrays for that, just place your str inside parenthesis. e.g.:

arr=("first second third")
echo ${arr[1]}

str="first second third"
arr1=($str)
echo ${arr1[1]}
2
  • 2
    This is the best approach thanks its very simple and not an errorpron. May 12, 2021 at 7:51
  • The only sane solution. Every other solution either invokes external third-party commands that may not necessarily be available or behave as expected under the current platform (e.g., awk) or performs fragile string-munging guaranteed to fail in obvious corner cases (e.g., echo "${x##* }"). Mar 15, 2022 at 3:56
5

you can use awk:

echo "rtcpOnNbActive         true" | awk '{print $NF}'
true

NF number of field in the current record

using sed:

echo "rtcpOnNbActive         true" | sed 's/.* //g'
true

using string expression:

 a="rtcpOnNbActive         true"
 echo ${a##* }
 true

using grep:

 echo "rtcpOnNbActive         true" | grep -Eo "[a-z]+$"
 true

-o is gives only exact match, [a-z]+ will match letter from a-z and $ means at end

4
  • 3
    Don't post content of other answer for yours in the same question, please. Dec 13, 2014 at 10:09
  • 1
    what others answers????
    – Hackaholic
    Dec 13, 2014 at 10:10
  • he can save it in variable its not a big deal here
    – Hackaholic
    Dec 13, 2014 at 10:14
  • echo is not portable for anything other than a literal string that doesn't start with - and doesn't contain any escape sequences. Its behavior varies even for the bash builtin, depending on how it was compiled, and whether XPG_ECHO is set. Also, you should always double quote variable expansions and command substitution (with certain exceptions, where it's not necessary but it doesn't do any harm either). With a string like the OP's, this should be fine, but if you want to make sure printf '%s\n' "${a##* }" would be better.
    – alexia
    Dec 13, 2014 at 13:03
2

You could use the read built-in

read -r _ y <<<"$x"
printf "%s\n" "$y"
true
3
  • why involve read? It isn't read that does the split - it is $IFS. For some reason a lot of people consider it ok to split w/ $IFS only when read is involved. You can just do: set -f; IFS=' '; printf %.0s%s $x or whatever. In any case - you need to specify $IFS's value here.
    – mikeserv
    Dec 14, 2014 at 1:58
  • @mikeserv, it's read doing the splitting using IFS, check the documentation. The main advantage with using read is that it sets variables (which is an OP requirement) and given that it can split strings and populate an array, is good for extracting arbitrary fields from a string. Additionally, I am assuming default IFS here, but it's easy enough to set if needed, IFS=$' \n\t' read -r _ y <<<"$x" will do the trick
    – iruvar
    Dec 14, 2014 at 3:42
  • no, its not. read assigns, $IFS splits. if you want to populate an array, use set - you dont need the artificial here-string nonsense in that case. unset IFS gets default $IFS behavior.
    – mikeserv
    Dec 14, 2014 at 4:57
1

Word splitting in bash can be accomplished very succinctly with set builtin.

str="rtcpOnNbActive                       true"
# Expand positional parameters with arguments
set -- $str
# Now $1=rtcpOnNbActive and $2=true

This can be extended to a host of scenarios by altering value of IFS variable, e.g:

ip_address="10.0.0.138"
IFS=.
set -- $ip_address
# $1=10, $2=0, $3=0, $4=138
-1

Pretty straightforward.

x="rtcpOnNbActive                       true"
y=${x* }

The ${x*.} removes everything from the space forward and then assigns that value to y.

Very similar to what Hackaholic listed above, but a little more succinct.

You must log in to answer this question.

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