Bug echo-ing multiple numerical values separated by commas - linux

I have a weird bug, basically I have set up a function to run remote commands via SSH on a box and get the lan MAC address and some other info. I want to write this info into a csv file.
When I run BOXLANMAC=$(remote_command "ifconfig eth0 | grep HWaddr | cut -d' ' -f11") I can echo $BOXLANMAC and get the expected output.
However, when I run echo $BOXLANMAC,$BOXLANMAC I get ,XX:XX:XX:XX:XX:XX where I expect to see XX:XX:XX:XX:XX:XX,XX:XX:XX:XX:XX:XX. I have tried many permutations of the echo command, using quotes and escape characters for the comma, but not had any success. I'm sure this is really simple and I should have been able to figure it out, but google seems to just get me results about splitting strings on commas.

As das.cyklone and I mentioned above, you might want to see if the remote command is returning whitespaces which are affecting the output of the echo command. Perhaps using tr to remove any whitespaces from the $boxlanmac variable will solve the problem. See How to trim whitespace from a Bash variable? for ways to do this.

Your example seems to work fine during testing. I can offer two suggestions:
1) Use awk instead of cut for whitespace. It's more reliable and easier to test.
2) If echo isn't working, try printf. It gives you more control with statements.
~-> BOXLANMAC=$(ifconfig eth0 | grep HWaddr | awk '{ print $5 }')
~-> echo ${BOXLANMAC}
78:2B:CB:88:E5:AR
~-> echo ${BOXLANMAC},${BOXLANMAC}
78:2B:CB:88:E5:AR,78:2B:CB:88:E5:AR
~-> printf "%s,%s\n" ${BOXLANMAC} ${BOXLANMAC}
78:2B:CB:88:E5:AR,78:2B:CB:88:E5:AR
~->
Good luck.

Have you tried: echo ${BOXLANMAC},${BOXLANMAC} ?

Related

sed not working on a variable within a bash script; requesting a file. Simple example

If I declare a variable within a bash script, and then try to operate on it with sed, I keep getting errors. I've tried with double quotes, back ticks and avoiding single quotes on my variable. Here is what I'm essentially doing.
Call my script with multiple parameters
./myScript.sh apples oranges ilike,apples,oranges,bananas
My objective is to use sed to replace $3 "," with " ", then use wc -w to count how many words are in $3.
MyScript.sh
fruits="$3"
checkFruits= sed -i 's/,/ /g' <<< "$fruits"
echo $checkFruits
And the result after running the script in the terminal:
ilike,apples,oranges,bananas
sed: no input files
P.s. After countless google searches, reading suggestions and playing with my code, I simply cannot get this easy sample of code to work and I'm not really sure why. And I can't try to implement the wc -w until I move past this block.
You can do
fruits="$3"
checkFruits="${3//,/ }"
# or
echo "${3//,/ }"
The -i flag to sed requires a file argument, without it the sed command does what you expect.
However, I'd consider using tr instead of sed for this simple replacement:
fruits="$3"
checkFruits="$(tr , ' ' <<< $fruits)"
echo $checkFruits
Looking at the larger picture, do you want to count comma-separated strings, or the number of words once you have changed commas into spaces? For instance, do you want the string "i like,apples,oranges,and bananas" to return a count of 4, or 6? (This question is moot if you are 100% sure you will never have spaces in your input data.)
If 6, then the other answers (including mine) will already work.
However, if you want the answer to be 4, then you might want to do something else, like:
fruits="$3"
checkFruits="$(tr , \\n <<< $fruits)"
itemCount="$(wc -l <<< $checkFruits)"
Of course this can be condensed a little, but just throwing out the question as to what you're really doing. When asking a question here, it's good to post your expected results along with the input data and the code you've already used to try to solve the problem.
The -i option is for inplace editing of input file, you don't need it here.
To assign a command's output to a variable, use command expansion like var=$(command).
fruits="$3"
checkFruits=$(sed 's/,/ /g' <<< "$fruits")
echo $checkFruits
You don't need sed at all.
IFS=, read -a things <<< "$3"
echo "${#things[#]}"

How to remove everything before a specific string

I need to get clean output from wireshark but recently i noticed that i've been getting outputs where my cut command doesn't work anymore
Data from wireshark
C.'¢¢#)ù¨.fEo³#(#¹³³÷÷P*,§ýý {P¹'GET /2015/dec/alltracks/playlist.m3u8
I used to use cut -f2 -d" " but now i notice some entries come with multiple spaces so my command fails.
How would I get rid of everything before GET, including the word GET? The goal is to get only /2015/dec/alltracks/playlist.m3u8
Use GNU grep in PCRE-mode enabled by -P flag and -o flag to print only the matching word.
grep -Po ".*GET \K(.*)" input-file
/2015/dec/alltracks/playlist.m3u8
Using a perl regEx
perl -nle 'print "$1" if /.*GET (.*)/' input-file
/2015/dec/alltracks/playlist.m3u8
You can do this by using the following regular expression
.*GET
Where .* recognises any characters (the * means zero or more) and GET recognises what you want including the leading space, so the output would be what you desire
sed "s/.*GET //g"
We would replace what we find with nothing (//).
s is for substitute while g is for global (which, depending on the case may or may not be necessary, although I'd recommend you to use it if you are willing to modify more than a line.

Awk pattern always matches last record?

I'm in the process of switching from zsh to bash, and I need to produce a bash script that can remove duplicate entries in $PATH without reordering the entries (thus no sort -d magic). zsh has some nice array handling shortcuts that made it easy to do this efficiently, but I'm not aware of such shortcuts in bash. I came across this answer which has gotten me 90% of the way there, but there is a small problem that I would like to understand better. It appears that when I run that awk command, the last record processed incorrectly matches the pattern.
$ awk 'BEGIN{RS=ORS=":"}!a[$0]++' <<<"aa:bb:cc:aa:bb:cc"
aa:bb:cc:cc
$ awk 'BEGIN{RS=ORS=":"}!a[$0]++' <<<"aa:bb:cc:aa:bb"
aa:bb:cc:bb
$ awk 'BEGIN{RS=ORS=":"}!a[$0]++' <<<"aa:bb:cc:aa:bb:cc:" # note trailing colon
aa:bb:cc:
I don't understand awk well enough to know why it behaves this way, but I have managed to work around the issue by using an intermediate array like so.
array=($(awk 'BEGIN{RS=":";ORS=" "}!a[$0]++' <<<"aa:bb:cc:aa:bb:cc:"))
# Use a subshell to avoid modifying $IFS in current context
echo $(export IFS=":"; echo "${array[*]}")
aa:bb:cc
This seems like a sub-optimal solution however, so my question is: did I do something wrong in the awk command that is causing false positive matches on the final record processed?
The last record in your original string is cc\n which is different from cc. When unsure what's happening in any program in any language, adding some print statements is step 1 to debugging/investigating:
$ awk 'BEGIN{RS=ORS=":"} {print "<"$0">"}' <<<"aa:bb:cc:aa:bb:cc"
<aa>:<bb>:<cc>:<aa>:<bb>:<cc
>:$
If you want the RS to be : or \n then just state that (with GNU awk at least):
$ awk 'BEGIN{RS="[:\n]"; ORS=":"} !a[$0]++' <<<"aa:bb:cc:aa:bb:cc"
aa:bb:cc:$
The $ in all of the above is my prompt.
Another possible workaround instead of your bash array solution
$ echo "aa:bb:cc:aa:bb:cc" | tr ':' '\n' | awk '!a[$0]++' | paste -sd:
aa:bb:cc

shell script grep only working on last line of file

I have a very strange problem I've never encountered and could not find anything related on other posts here, I have a shell script that just greps a test host file(will use real one once this works) in a while loop but it will only output the last line:
#!/bin/bash
while read line
do
grep $line /etc/test/hosts
done < temp-file.txt
here is the /etc/test/hosts file:
device1 192.168.0.1
device2 192.168.0.2
device3 192.168.0.3
// cut
device50 192.168.0.50
the temp-file.txt is identical to the test host file for testing
And as mentioned, here is the output - only showing last line:
device3 192.168.0.50
If I change the grep command to just echo $line it outputs correctly. I have tried changing the number of lines in the test host file to be more and less but same result. I have also done the grep command from cli and it works fine on every device I grep for. I have also tried putting the $line in double quotes but that also has not changed anything.
I have also tried an alternate while loop using the while IFS="\n" method but same results. This seems like it should be extraordinarily simple but I'm having issues. Am I doing something wrong or is this maybe a bug in bash?
question answered by Eric Renouf via comment.
solution:
add sed -i 's/\r$//' temp-file.txt to top of script to remove the \r that were at the end of each line.

Matching strings in a bash case statement and finding the current wireless network

I've got a bash script (for personal use), part of which prints a message depending on which network I'm connected to. As part of this I want to look at the ID of the currently connected wireless network.
What I'm doing is parsing the wireless name out of the output of iwconfig and I want to print out the name, or a special message for certain networks:
SSID=`iwconfig wlan0|grep "ESSID:" | sed "s/.*ESSID:\"\(.*\)\"/\1/"` 2>/dev/null
case "$SSID" in
StaffOnly)
echo "Staff only network at Work" ;;
*)
echo "You're on a wireless network called $SSID"
esac
The second part of this (printing the name of whatever network I'm connected to) works, but the special case of being on the StaffOnly network doesn't match and falls through the other one.
I'd like to know what I'm doing wrong with the case statement. And also if there's just a better way of doing this anyway.
The sed command lacks trailing .*. It should be:
SSID=`iwconfig wlan0|grep "ESSID:" | sed "s/.*ESSID:\"\(.*\)\".*/\1/"` 2>/dev/null
^^ HERE!
Without that you are leaving the end of the line in and it apparently contains some whitespace that's causing mismatch for you.
Several related notes:
The redirection should go inside the backquote:
SSID=`iwconfig wlan0|grep "ESSID:" | sed "s/.*ESSID:\"\(.*\)\".*/\1/" 2>/dev/null`
$() is generally preferred over backquote, because it can nest:
SSID=$(iwconfig wlan0|grep "ESSID:" | sed "s/.*ESSID:\"\(.*\)\".*/\1/" 2>/dev/null)
When doing debug prints, always add some delimiters around the variable content so you see any leading and trailing whitespace.
You don't need sed. It can all be done using grep as follows:
SSID=$(iwconfig wlan0 | grep -oP '(?<=ESSID:")[^"]*')

Resources