nslookup capture stderr in a variable and display - shell

In a shell script I am running nslookup on number of URLs
Sometimes some url returns cannot resolv error. I need to capture those errors in a variable.
here is code for nslookup which gets ip address returned
output=$(nslookup "$URL" | grep Add | grep -v '#' | cut -f 3 -d ' ' | awk 'NR>1' )
Now in same variable output, I want to capture the error
nslookup: can't resolve
Stdout I am capturing in a file.
I have tried different version of re-directions - 2>&1 and others but error does not get assigned to variable. I do not want the error to be re-directed to separate file but want it to be recorded in above output variable.

As long as you are using awk, you can simplify things considerably
nslookup "$URL" 2>&1 |
awk -e '/Add/ && !/#/ && NR > 1 {print $2}'
-e '/resolve|NXDOMAIN/ { print "error" }'
Where one line has been broken into three for clarity. I cannot reproduce the problem you say you have 2&>1 nor do I believe it should fail.

The redirection of stderr works when you use
output=$(nslookup "$URL" 2>&1 | grep Add | grep -v '#' | cut -f 3 -d ' ' | awk 'NR>1')
but it is futile since you filter it out immediately with the grep Add. You need to rethink your logic and what you really want. Maybe a better approach is
output=$(nslookup "$URL" 2>&1)
case $output in
(nslookup:*) ;;
(*) output=$(echo "$output" | grep Add | ...);;
esac

Related

How to parse a string of a kubectl cmd output in a shell script?

kubectl get nodes -o name gives me the output
node/k8s-control.anything
node/k8s-worker1.anything
I need to get only
control
worker1
as output and want to iterate through these elements
for elm in $(kubectl get nodes -o name); do echo "$elm" >> file.txt; done
So the question is how to get the string between node/k8s- and .anything and iterate these in the for loop.
You can for example use cut twice, first to get a part after - and
then to get a part before .:
for elm in $(kubectl get nodes -o name | cut -d- -f2 | cut -d. -f1); do echo "$elm" >> file.txt; done
With awk
kubectl get nodes -o name | awk -F'[.-]' '{print $2}' > file.txt
You can use grep with -oP filter to extract the desired substring. Later, you can use > operator to redirect to the file.txt.
kubectl get nodes -o name|grep -oP 'node.*?-\K[^.]+'
control
worker1
Another option might be bash parameter expansion:
while read -r line ; do line="${line#*-}"; line="${line%.*}"; printf "%s\n" "$line" ; done < <(kubectl get nodes -o name)

grep return the string in between words

I am trying to use grep to filter out the RDS snapshot identifier from the rds describe-db-snapshots command output below:
"arn:aws:rds:ap-southeast-1:123456789:snapshot:rds:apple-pie-2018-05-06-17-12",
"rds:apple-pie-2018-05-06-17-12",
how to return the exact output as in
rds:apple-pie-2018-05-06-17-12
tried using
grep -Eo ",rds:"
but not able to
Following awk may also help you on same.
awk 'match($0,/^"rds[^"]*/){print substr($0,RSTART+1,RLENGTH-1)}' Input_file
Your grep -Eo ",rds:" is failing for different reasons:
You did not add a " in the string to match
Between the comma and rds you need to match the character.
You are trying to match the comma that can be on the previous line
Your sample input is 2 lines (with a newline in between), perhaps the real input is without the newline.
You want to match until the next double quote.
You can support both input-styles (with/without newline) with
grep -Eo '(,|^)"rds:[^"]*' rdsfile |cut -d'"' -f2
You can do this in one command with
sed -rn 's/.*(,|^)"(rds:[^"]*).*/\2/p' rdsfile
EDIT: Manipulting stdout and not the file is with similar commands:
yourcommand | grep -Eo '(,|^)"rds:[^"]*' |cut -d'"' -f2
# or
yourcommand | sed -rn 's/.*(,|^)"(rds:[^"]*).*/\2/p'
You can also test the original commands with yourcommand > rdsfile.
You might notice that rdsfile is missing data that you have seen on the screen, in that case add 2>&1
yourcommand 2>&1 | grep -Eo '(,|^)"rds:[^"]*' |cut -d'"' -f2
# or
yourcommand 2>&1 | sed -rn 's/.*(,|^)"(rds:[^"]*).*/\2/p'

creating a variable from sed output

I am banging my head against the keyboard on this simple piece of code.
#!/bin/bash
connstate="Connected"
vpnstatus=$(/opt/cisco/anyconnect/bin/vpn state | (grep -m 1 'state:'))
echo $vpnstatus
vpnconn=$(echo $vpnstatus | sed -e 's/>>\ state: //g' | sed "s/ //g")
echo "$vpnconn" "$connstate"
if [ "$vpnconn" = "$connstate" ];then
echo $vpnconn
else echo "this script still fails"
fi
echo done
This is the output from the above code:
>> state: Connected
Connected Connected
this script still fails
done
I believe the issue revolves around the vpnconn=$ if I comment that section of code out and fill the variable vpnconn="Connected" this code works fine. Something with how the sed is working on the input from vpnstatus and outputting the results to vpnconn is making what looks like a correct result incorrect when doing the compare in the if then.
I have tried splitting up the vpnconn line into two separate lines and that did not change anything, I took out the sed "s/ //g" and replaced it with a trim -d ' ' and that did not change the results. I know this is something small in this tiny piece of code that I am missing.
Did you try?
vpnconn=$(echo "$vpnstatus" | awk '{print $3}')
Something like:
vpnstatus=$(/opt/cisco/anyconnect/bin/vpn state|grep -m 1 'state:'|awk '{print 3}')
should do the work.

how to omit grep output in conditional statement

On a Mac, I want to determine if there are any sleep assertions present, using pmset. If there are, extract only that information and omit unnecessary information.
If grep returns nothing I want to print "Nothing".
if pmset -g | grep pre ; then pmset -g | grep pre | cut -d'(' -f2 | cut -d')' -f1 ; else printf "Nothing\n" ; fi
The problem is that the first grep result is printed, and so is the formatted one. For example this is what I get if a backup is in progress:
sleep 15 (sleep prevented by backupd)
sleep prevented by backupd
I don't want the first line, and want to discard it. I only want the second line to print ("sleep prevented by backupd").
If the grep result is empty I want to indicate that with the text "Nothing". The above script works OK for that.
There are probably many more elegant solutions but I've been searching days for one.
If i understand your question properly, you simply need to discard the output of first grep irrespective of the output it provides. If it's so, then you can use -q option provided by grep.
From the man page for 'grep':
-q, --quiet, --silent
Quiet; do not write anything to standard output. Exit immediately with zero status if any match is found, even if an error was
detected. Also see the -s or --no-messages option. (-q is specified by POSIX.)
Something like this:
if ifconfig | grep -q X; then
ifconfig | grep Mi | cut -d'(' -f2
else
printf "Nothing\n"
fi
Obviously in the above example, output of ifconfig will not change every time. Just used as an example. ;)
Redirect the output to /dev/null:
if pmset -g | grep pre >/dev/null 2>&1 ; then
pmset -g | grep pre | cut -d'(' -f2 | cut -d')' -f1
else
printf "Nothing\n"
fi
This is maybe a little more succinct. It gets grep to only output the part of the line that matches the pattern instead of the whole line, by using grep -o:
#!/bin/bash
SLEEP=$(pmset -g | grep -o "sleep prevented.*[^)]")
if [ -z "$SLEEP" ]; then
echo Nothing
else
echo $SLEEP
fi
The pattern is sleep prevented and any characters following until a ) is encountered.

what does grep -v '^#' do

My program looks like this.
ALL=`cat $1 | grep -v '^#' | wc -l`
FINISHED="0"
for i in `cat $1 | grep -v '^#'`; do
echo "PROBE $i"
I will be doing some operation
FINISHED=`echo $FINISHED"+1"|bc`
I will run this script by giving a file name as parameter where a list of probes will be present.
I have 2 questions
What does grep -v '^#' mean. I learnt that '^ is usually used to matching a particular string. But in the file name which I give there is no #. Moreover I am getting the total number of probes for cat $1 | grep -v '^#' | wc -l.
echo $FINISHED"+1"|bc. Here any idea as to why the developer as added |bc?
^ means "start of line"
# is the literal character #
-v means "invert the match" in grep, in other words, return all non matching lines.
Put those together, and your expression is "select all lines that do not begin with #"
| is the pipe character, it takes the output of the command on the left hand side, and uses it as the input of the command on the right hand side. bc is like a command line calculator (to do basic math).
I would use this to exclude comments from the code I'm reading. So all comment lines start with # and I don't want to see them if there are too many of them.
grep -v '^#'
We have different ways for calculation. Pick the one which you like.
a=`echo 1+1 | bc`; echo $a
b=$((1+1)); echo $b
c=`expr 1 + 1`; echo $c
let d=1+1; echo $d

Resources