10

Problem

I tried to extract the signal level for wifi in the following way, in a bash script (quotes seem to make no difference):

string="$(iwconfig wlan0 | grep -I Signal)"

If I echo $string, I get what I expect:

Link Quality=63/70 Signal level=-47dBm

But if I try to get a substring, echo ${string:5}, it returns the same thing.


Debuging:

If I paste the output of wconfig wlan0 | grep -I Signal directly into the variable: string="Link Quality=63/70 Signal level=-47dBm" then everything works as expected.

echo $string 
# Link Quality=63/70 Signal level=-47dBm
echo ${string:5}
# Quality=63/70 Signal level=-47dBm

Question: According to the internet, all bash variables are stored as character strings. Thus, the debugging result should have been the same as my original problem. Is there some reason it is not parsed as text in the original problem?

15

This is because echo $string doesn't simply print the value of string; it first perform a split+glob operation - one of the consequences of which is that leading whitespace is elided:

$ string=$(iwconfig wls1 | grep Signal)
$ echo $string
Link Quality=38/70 Signal level=-72 dBm

whereas

$ echo "$string"
          Link Quality=38/70  Signal level=-72 dBm  

We can see that there is a sequence of whitespace characters at the start of $string - in fact there are more than 5, so removing 5 still leaves a string with leading whitespace, which an unquoted substring expansion (${string:5}) also elides:

$ echo "${string:5}"
     Link Quality=38/70  Signal level=-72 dBm  
$ echo ${string:5}
Link Quality=38/70 Signal level=-72 dBm

For additional discussion see:

  • 4
    Tl;dr always quote your variables – gronostaj Aug 6 at 4:26
6

This works on my machine:

$ string="$(iwconfig wlp60s0 | grep -I Signal)"
$ echo $string
Link Quality=68/70 Signal level=-42 dBm
$ echo $string | cut -d' ' -f4,5
level=-42 dBm
  • For your machine replace wlp60s0 with wlan0.
  • Note this is using Ubuntu 16.04 and Ubuntu 19.04 where there is a space between 42 and dBm. As such the cut command is instructed to print fields #4 and #5. In your question there is no space so I'm not sure what version you are using.

You could also use:

$ echo $string | cut -d'=' -f3
-42 dBm
  • In this case cut is told to use = as field delimiter.

If you want to use ${string...} though the correct syntax is:

$ echo ${string##*=}
-38 dBm

$ echo "${string##*=}"
-38 dBm  

Either method will work to take the substring after the last =. The original method of 5 in your question I don't understand how it can work.

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.