Parsing a non-regular command output - linux

I have the following output of iperf version 2 running on LEDE OS. I am trying to parse the output to get the number before the Mbits/sec which is the average throughput of the IPERF session. However, it seems the separation between each column does not match certain number of spaces nor tabs. In addition, the CSV format generated by iperf generates strange results, as a result I have to rely on the regular output of iperf. Any suggestion how to parse the output using either regular expression or awk command?
The iperf command:
iperf -c 10.0.0.7 -t 10 -i 0.1 -f m
The output:
[ 3] 0.00-10.00 sec 1889 MBytes 1584 Mbits/sec 15114/0 0
2483K/3302 us

You can use grep for those.
iperf -c 10.0.0.7 -t 10 -i 0.1 -f m | grep -o -E '\w+ Mbits/sec'
OR to be more accurate:
iperf -c 10.0.0.7 -t 10 -i 0.1 -f m | grep -o -E '[0-9]+ Mbits/sec'
To get only the digits, you can use yet another regex,
iperf -c 10.0.0.7 -t 10 -i 0.1 -f m | grep -Po '[[:digit:]]+ *(?=Mbits/sec)'
Above, [[:digit:]]+ and [0-9]+ are same and matches the digits in the line.
For FreeBSD grep in MacOS X, -P will not work. Instead use perl directly,
iperf -c 10.0.0.7 -t 10 -i 0.1 -f m | perl -nle 'print $& if m{\d+ *(?=Mbits/sec)}'

You cat try to use awk tool :
iperf -c 10.0.0.7 -t 10 -i 0.1 -f m | awk -F 'MBytes' {'print $2'}

If this is iperf 2 then try -fb for bit/byte formatting. This format is easier to parse w/regular expressions as it's just a number. Man page is here.
`GENERAL OPTIONS
-f, --format [abkmgBKMG]
format to report: adaptive, bits, Bytes, Kbits, Mbits, Gbits, KBytes, MBytes, GBytes (see NOTES for more)`

Related

linux shell script stops after first line

I try to execute etherwake based on a MQTT topic.
The output of mosquitto_sub stops if I pipe it in a while statement.
works:
# mosquitto_sub -L mqtt://... | grep -o -E '([[:xdigit:]]{2}:){5}[[:xdigit:]]{2}'
00:00:00:00:de:ad
00:00:00:00:be:ef
00:00:00:00:ca:fe
(goes on and on)
does not work:
mosquitto_sub -L mqtt://... \
| grep -o -E '([[:xdigit:]]{2}:){5}[[:xdigit:]]{2}' \
| hexdump
Output stops after a single line:
0000000 1234 5678 9abc def0 abcd cafe 3762 3a65
The big picture is this one:
mosquitto_sub -L mqtt://... \
| grep -o -E '([[:xdigit:]]{2}:){5}[[:xdigit:]]{2}' \
| while read macaddr; do
echo "send WOL to " $macaddr;
/usr/bin/etherwake -D -b "$macaddr" 2>&1;
done
Usually I am fine with the Linux shell but this time it simply gets stuck after the first line.
My guess is there is some problem with stdin or stdout (is not read or full etc.) in some kind. But I am out ideas.
By the way its an OpenWRT shell so an ash and no bash.
The problem is indeed the "buffering" of grep when used with pipes.
Usually the '--line-buffered' switch should be used to force grep to process the data line by line instead of buffer the data.
Because grep on OpenWRT (busybox) does not have this switch 'awk' is used:
mosquitto_sub -L mqtt://... \
| awk '/([[:xdigit:]]{2}:){5}[[:xdigit:]]{2}/{ print $0 }' \
| hexdump
If there is no busybox version of grep used the solution would be like:
mosquitto_sub -L mqtt://... \
| grep -o --line-buffered -E '([[:xdigit:]]{2}:){5}[[:xdigit:]]{2}' \
| hexdump
Thank you all a lot for your help.

Bash/SH, Same command different output?

$ cat a.sh
#!/bin/bash
echo -n "apple" | shasum -a 256
$ sh -x a.sh
+ echo -n apple
+ shasum -a 256
d9d20ed0e313ce50526de6185500439af174bf56be623f1c5fe74fbb73b60972 -
$ bash -x a.sh
+ echo -n apple
+ shasum -a 256
3a7bd3e2360a3d29eea436fcfb7e44c735d117c42d1c1835420b6b9942dd4f1b -
And the last one is correct.
Why is that? and how to solve it?
Per POSIX, echo supports no options.
Therefore, when echo -n is run with sh, it outputs literal -n instead of interpreting -n as the no-trailing-newline option:
$ sh -c 'echo -n "apple"'
-n apple # !! Note the -n at the beginning.
Note: Not all sh implementations behave this way; some, such as on Ubuntu (where dash acts as sh), do support the -n option, but the point is that you cannot rely on that, if your code must run on multiple platforms.
The portable POSIX-compliant way to print to stdout is to use the printf utility:
printf %s "apple" | shasum -a 256

Bash: store redis-benchmark result to var generate strange string

I try to parse redis-benchmark result in shell script, I write the script but failed to execute.
Environment
$ bash --version
GNU bash, version 4.2.24(1)-release (x86_64-pc-linux-gnu)
$ cat /etc/issue
Ubuntu 12.04 LTS \n \l
$ dpkg -l |grep redis
2:2.8.19-rwky1~precise
$ cat demo.sh
OUTPUT=`redis-benchmark -n 1000 -r 100000 -d 32 -c 30 -t GET -p 6379 -q |grep 'per second'`
R=$(echo "$OUTPUT" | cut -f 1 -d'.')
S=$(echo $R | awk '{print $2}')
echo $S
Shell debug show some confuse information.
$ bash -x demo.sh
++ redis-benchmark -n 1000 -r 100000 -d 32 -c 30 -t GET -p 6379 -q
++ grep 'per second'
GET: 166666.67 requests per second'
GET: 166666.67 requests per second'
++ cut -f 1 -d.
GET: 166666'an
++ echo GET: $'-nan\rGET:' 166666
++ awk '{print $2}'
+ S=$'-nan\rGET:'
+ echo $'-nan\rGET:'
GET:
Do I miss something?
Comments
Looks due to redis-benchmark result is something strange, don't know why
$ redis-benchmark -n 1000 -r 100000 -d 32 -c 30 -t GET -p 6379 -q |grep per > todo
$ vim todo
GET: -nan^MGET: 166666.67 requests per second
If you will not be able to fix the redis-benchmark output, this will parse both the correct and strange formats:
redis-benchmark -n 1000 -r 100000 -d 32 -c 30 -t GET -p 6379 -q | grep 'per second' | sed 's/.*GET: \(.*\) requests .*/\1/'
But you should probably fix the input :D

wc -c and wc -m give the same output all the time?

I am having the following doubt. wc -m and wc -c are always giving same output. I tried with floating point numbers also but the output is same for both the commands.
cat test | wc -m
541
cat test | wc -c
541
ASCII character takes byte. But UTF-8 local charaters takes 2 bytes.
echo -n "ŻÓŹŁŃĘ"|wc -m
6
echo -n "ŻÓŹŁŃĘ"|wc -c
12
P.S. You can wc -m test to save cat.

Bash - Command call ported to variable with another variable inside

I believe this is a simple syntax issue on my part but I have been unable to find another example similar to what i'm trying to do. I have a variable taking in a specific disk location and I need to use that location in an hdparm /grep command to pull out the max LBA
targetDrive=$1 #/dev/sdb
maxLBA=$(hdparm -I /dev/sdb |grep LBA48 |grep -P -o '(?<=:\s)[^\s]*') #this works perfect
maxLBA=$(hdparm -I $1 |grep LBA48 |grep -P -o '(?<=:\s)[^\s]*') #this fails
I have also tried
maxLBA=$(hdparm -I 1 |grep LBA48 |grep -P -o '(?<=:\s)[^\s]*')
maxLBA=$(hdparm -I "$1" |grep LBA48 |grep -P -o '(?<=:\s)[^\s]*')
Thanks for the help
So I think here is the solution to your problem. I did basically the same as you but changed the way I pipe the results into one another.
grep with regular expression to find the line containing LBA48
cut to retrieve the second field when the resulting string is divided by the column ":"
then trim all the leasding spaces from the result
Here is my resulting bash script.
#!/bin/bash
target_drive=$1
max_lba=$(sudo hdparm -I "$target_drive" | grep -P -o ".+LBA48.+:.+(\d+)" | cut -d: -f2 | tr -d ' ')
echo "Drive: $target_drive MAX LBA48: $max_lba"

Resources