0

I`m try to check my ttl value with alias in .bashrc file by function like this:

# awk ttl
function awkTTL() {

ping 8.8.8.8 -c 1 | grep 'ttl' | awk -F '[ :=]' '{print $9}'

}

# check connection
function checkOnline() {

awkTTL

if [[ awkTTL -ge 2 ]]; then
    echo "online"
else
    echo "offline"
fi
}

alias -g ww=checkOnline

and always i got answer like this

107 # current ttl value
offline # echo from function
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
a1i3n
  • 7
  • 3
  • 3
    Note that `function somefunc() {` is bad practice; just use `somefunc() {`. See https://wiki.bash-hackers.org/scripting/obsolete – Charles Duffy Jan 21 '21 at 22:09
  • That said, it's not clear in the question why you think anything that happens is wrong. What output do you _expect_? Ideally, make that explanation of what's wrong part of the title -- and test that the code in the question produces that same problem when run with no changes whatsoever (the "reproducible" part of the [mre] definition; note also the "minimal" part). – Charles Duffy Jan 21 '21 at 22:10
  • 2
    ...make the title talk about _your specific problem_, not about you, or about the fact that you have a problem. "Script adds word `smaller` to output", for example, would be such a better title, if that is in fact what you want help with. – Charles Duffy Jan 21 '21 at 22:12
  • 1
    (Also, why make a `ww` alias, instead of just naming your function `ww` in the first place?) – Charles Duffy Jan 21 '21 at 22:23
  • 3
    ... also you probably want `[[ $(awkTTL) -ge 2 ]]` – Charles Duffy Jan 21 '21 at 22:23
  • 3
    @AlikSei : Charles Duffy is right, of course, but to your original question, **what** you did wrong: In ``[[ awkTTL -ge 2 ]]``, the `-ge` operator expects two numbers as operands, but _awkTTL_ is just a 6-letter-string, not a number. – user1934428 Jan 22 '21 at 08:40
  • @Charles Duffy Thanks a lot for you comments! "smaller" coming from before whens my echo was like "bigger" and "smaller" – a1i3n Jan 22 '21 at 13:45
  • 1
    `grep | awk` is an anti-pattern. Awk should do the grepping. – Jens Jan 22 '21 at 14:00
  • 1
    BTW, I don't recommend parsing `ping`'s output this way. Not all versions of `ping` will have your TTL number show up in `$9`; it's also liable to be different depending on your current locale setting, so there are lots of ways for this script to unexpectedly break. Better to match a `ttl=([[:digit:]]+)` regex and not assume that the number of columns before or after will match what you expect. – Charles Duffy Jan 22 '21 at 14:18
  • Since you're invoking `awk`, you might as well do the comparison there as well. ie, in awk write `{return $9 < 2}` and just check the value returned by the function with `if awkTTL; then ....` – William Pursell Jan 22 '21 at 14:48

2 Answers2

1

First, all the below assumes that your ping command has output formatted such that your original awk works as-is. If that assumption isn't true (and not all ping commands do work with that, f/e, one I'm trying to test with puts the value in $10 instead of $9), the below examples (except for the pure-bash one that doesn't use awk at all) aren't expected to work either.


A better implementation of the checkOnline function could look like:

# caution: this awk code doesn't work for all versions of ping
awkTTL() { ping 8.8.8.8 -c 1 | awk -F '[ :=]' '/ttl/ {print $9}'; }

checkOnline() {
  if [[ $(awkTTL) -ge 2 ]]; then
    echo "online"
  else
    echo "offline"
  fi
}

Using a command substitution (the $( ... ) syntax) means we're putting the output of running awkTTL into the [[ argument list, instead of the string 'awkTTL'. Because the string 'awkTTL' isn't a number, attempts to compare it against a number fail.


By the way, you could also just do the whole thing in awk, and not need bash to read or compare awk's output at all:

# note that this still assumes ttl is in $9, per the OP's original code
checkOnline() {
  awk -F '[ :=]' '
    BEGIN                          { ttl=0 }
    /ttl/ && $9 ~ /^[[:digit:]]+$/ { ttl=$9 }
    END   { if (ttl >= 2) { print "online" } else { print "offline" } }
  ' < <(ping 8.8.8.8 -c1)
}

...or, to do the whole thing in bash, without any need for awk:

checkOnline() {
  local line highestTTL=0
  while IFS= read -r line; do
    if [[ $line =~ [[:space:]]ttl=([[:digit:]]+)([[:space:]]|$) ]]; then
      highestTTL=${BASH_REMATCH[1]}
    fi
  done < <(ping 8.8.8.8 -c 1)
  if (( highestTTL >= 2 )); then
    echo "online"
  else
    echo "offline"
  fi
}
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • Your 2nd example without awk return opposite value – a1i3n Jan 22 '21 at 14:42
  • @AlikSei, I can't prove whether that's true, or test proposed changes, without output from your copy of `ping`. `$9` isn't the right column _at all_ with my copy. – Charles Duffy Jan 22 '21 at 14:57
  • @AlikSei, however, see the online interpreter at https://ideone.com/myfOFB, giving correct output in both online and offline cases. (The only change in that code from what's given in the answer is that it reads ping's output on its stdin, instead of starting a new copy of ping itself). – Charles Duffy Jan 22 '21 at 15:01
  • Thank you for your attention! This is what i mean in my firs comment: https://ideone.com/PjGFna – a1i3n Jan 22 '21 at 15:16
  • @AlikSei, from your link, `ping: socket: Operation not permitted` -- the ideone sandbox is _always_ offline. That's why you need to take out the `< <(ping 8.8.8.8 -c 1)` and instead hardcode the output `ping` would have in each case to test there. – Charles Duffy Jan 22 '21 at 15:17
  • @AlikSei, ...after taking that out, the output is https://ideone.com/TS5jlF, working correctly. – Charles Duffy Jan 22 '21 at 15:18
-1

awkTTL in this case is echoing directly to the console, so you won't be able to easily capture the value for a test in your if statement. I would recommend instead having the awkTTL function return the value, which could be captured or echoed:

function awkTTL() {
  ping 8.8.8.8 -c 1 | grep 'ttl' | awk -F '[ :=]' '{print $9}'
}

function checkOnline() {
  ttl = $(awkTTL) # capture value from the function
  echo $ttl
  if [[ $ttl -ge 2 ]]; then
    echo 'online'
  else
    echo 'offline'
  fi
}

I have no idea where your "smaller" string is coming from. Only guess here is that is from a previous version of the script that is being executed instead of the one you posted.

PaulProgrammer
  • 16,175
  • 4
  • 39
  • 56
  • 2
    `ttl = $(awkTTL)` isn't an assignment in bash; it's running the command `ttl` with `=` as its first argument. It'll fail with a "command not found", as discussed in https://stackoverflow.com/questions/2268104/command-not-found-error-in-bash-variable-assignment. – Charles Duffy Jan 21 '21 at 22:15
  • 1
    Also, `echo $ttl` has the bugs discussed in https://stackoverflow.com/questions/29378566/i-just-assigned-a-variable-but-echo-variable-shows-something-else – Charles Duffy Jan 21 '21 at 22:15
  • 1
    And `grep foo | awk '{...}'` is generally better replaced with `awk '/foo/ {...}'`; no reason for `grep` when you're already running `awk`, which has a superset of its functionality. – Charles Duffy Jan 21 '21 at 22:16
  • 2
    @PaulProgrammer : I strongly suggest to declare `ttl` as local variable, otherwise if you use this function, it would clobber a `ttl` variable defined in the calling process. – user1934428 Jan 22 '21 at 08:41