Bash variable from command with pipes, quotes, etc - bash

I have a command I'm using to get the hostname.localdomain:
dig axfr #dc1.localdomain.com localdomain.com | grep -i Lawler | awk '{ getline ; $1=substr($1,1,length($1)-1); print $1 ; exit }'
This nicely returns a result like:
michael.lawler.localdomain.com
I'd like to further use that result as a variable in a Bash script.
It seems I'm having trouble getting past the first pipe.
If I VAR="dig axfr #dc1.localdomain.com localdomain.com | grep -i Lawler | awk '{ getline ; $1=substr($1,1,length($1)-1); print $1 ; exit }'"
...I get back the entire zone transfer. I've also tried many minor changes, adding $ before the dig command, without quotes, but nothing seems to work. How can I fix this?

VAR=$( dig axfr #dc1.localdomain.com localdomain.com |
grep -i Lawler |
awk '{ getline ; $1=substr($1,1,length($1)-1); print $1 ; exit }' )

Use backtics instead of quotes:
VAR=`dig axfr #dc1.localdomain.com localdomain.com | grep -i Lawler | awk '{ getline ; $1=substr($1,1,length($1)-1); print $1 ; exit }'`
Backtics actually mean "run whatever is in here and return standard out as the expression's value", but quotes don't do that.

Related

shell script in a here-document used as input to ssh gives no result

I am piping a result of grep to AWK and using the result as a pattern for another grep inside EOF (not sure whats the terminology there), but the AWK gives me blank results. Below is part of the bash script that gave me issues.
ssh "$USER"#logs << EOF
zgrep $wgr $loc$env/app*$date* | awk -F":" '{print $5 "::" $7}' | awk -F"," '{print $1}' | sort | uniq | while read -r rid ; do
zgrep $rid $loc$env/app*$date*;
done
EOF
I am really drawing a blank here beacuse of no error and Im out of ideas.
Samples:
I am greping log files that looks like below:
app-server.log.2020010416.gz:2020-01-04 16:00:00,441 INFO [redacted] (redacted) [rid:12345::12345-12345-12345-12345-12345,...
I am interested in rid and I can grep that in logs again:
zgrep $rid $loc$env/app*$date*
loc, env and date are working properly, but they are outside of EOF.
The script as a whole connects to ssh and goes out properly but I am getting no result.
The immediate problem is that the dollar signs are evaluated by the local shell because you don't (and presumably cannot) quote the here document (because then $wqr and $loc etc will also not be expanded by the shell).
The quick fix is to backslash the dollar signs, but in addition, I see several opportunities to get rid of inelegant or wasteful constructs.
ssh "$USER"#logs << EOF
zgrep "$wgr" "$loc$env/app"*"$date"* |
awk -F":" '{v = \$5 "::" \$7; split(v, f, /,/); print f[1]}' |
sort -u | xargs -I {} zgrep {} "$loc$env"/app*"$date"*
EOF
If you want to add decorations around the final zgrep, probably revert to the while loop you had; but of course, you need to escape the dollar sign in that, too:
ssh "$USER"#logs << EOF
zgrep "$wgr" "$loc$env/app"*"$date"* |
awk -F":" '{v = \$5 "::" \$7; split(v, f, /,/); print f[1]}' |
sort -u |
while read -r rid; do
echo Dancing hampsters "\$rid" more dancing hampsters
zgrep "\$rid" "$loc$env"/app*"$date"*
done
EOF
Again, any unescaped dollar sign is evaluated by your local shell even before the ssh command starts executing.
Could you please try following. Fair warning I couldn't test it since lack of samples. By doing this approach we need not to escape things while doing ssh.
##Configure/define your shell variables(wgr, loc, env, date, rid) here.
printf -v var_wgr %q "$wgr"
printf -v var_loc %q "$loc"
printf -v var_env %q "$env"
printf -v var_date %q "$date"
ssh -T -p your_pass user#"$host" "bash -s $var_str" <<'EOF'
# retrieve it off the shell command line
zgrep "$var_wgr $var_loc$var_env/app*$var_date*" | awk -F":" '{print $5 "::" $7}' | awk -F"," '{print $1}' | sort | uniq | while read -r rid ; do
zgrep "$rid $var_loc$var_env/app*$date*";
done
EOF

Adding value to global variable in a subshell is not working

I am trying to get the total disk usage of my machine. Below is the script code:
#!/bin/sh
totalUsage=0
diskUse(){
df -H | grep -vE '^Filesystem|cdrom' | awk '{ print $5 " " $1 }' | while read output;
do
diskUsage=$(echo $output | awk '{ print $1}' | cut -d'%' -f1 )
totalUsage=$((totalUsage+diskUsage))
done
}
diskUse
echo $totalUsage
While totalUsage is a global variable, I have tried to sum the individual disk usage to totalUsage in the line:
totalUsage=$((totalUsage+diskUsage))
An echo of totalUsage between do and done shows the correct value,
but when I try to echo it after my call diskUse, it stills prints a 0
Can you please help me, what is wrong here?
The variable totalUsage in a sub-shell doesn't change the value in the parent shell.
Since you tagged bash, you can use here string to modify your loop:
#!/bin/bash
totalUsage=0
diskUse(){
while read output;
do
diskUsage=$(echo $output | awk '{ print $1}' | cut -d'%' -f1 )
totalUsage=$((totalUsage+diskUsage))
done <<<"$(df -H | grep -vE '^Filesystem|cdrom' | awk '{ print $5 " " $1 }')"
}
diskUse
echo $totalUsage
I suggest to insert
shopt -s lastpipe
as new line after
#!/bin/bash
From man bash:
lastpipe: If set, and job control is not active, the shell runs the last command of a pipeline not executed in the background in the current shell environment.

Tail -Fn0 and variable

This follows on from Faulty tail syntax or grep command? but I'm reading a live log entries for given conditions and when they're met continuing the execution of the rest of the script. I'm using this:
tail -Fn0 /var/log/messages | grep -q "CPU utilization" | grep -q "exceeded threshold"
FPC=$(echo $line | awk 'END { print substr($8,1,1) }')
PIC=$(echo $line | awk 'END { print substr($11,1,1) }')
echo FPC $FPC
echo PIC $PIC
echo "Running information gathering"...and rest of script.
Which works perfectly for the conditions detection and further execution, but I don't have the log entry to test for the FPC and PIC variables. I've tried wrapping the tail statement thus:
line=$(tail -Fn0 /var/log/messages | grep -q "CPU utilization" | grep -q "exceeded threshold")
but grep -q exits silently and the $line variable is blank. I've tried:
line=$(tail -Fn0 /var/log/messages | grep -m1 "CPU utilization" | grep -m1 "exceeded threshold")
which doesn't work until I attempt to CONTROL-C out of the script. Then it works fine and continues perfectly. Can someone help please?
I need the variables FPC and PIC later in the script.
Assuming that you don't need these variables later on, you could do something like this:
tail -Fn0 /var/log/messages | \
awk '/CPU utilization/ && /exceeded threshold/ {
print "FPC", substr($8,1,1); print "PIC", substr($11,1,1); exit }'
When the line matches both patterns, print the two parts of it that you are interested in and exit.
If you do need the variables, you could do something like this instead:
line=$(tail -Fn0 /var/log/messages | awk '/CPU utilization/&&/exceeded threshold/{print;exit}')
FPC=$(echo "$line" | awk '{ print substr($8,1,1) }')
PIC=$(echo "$line" | awk '{ print substr($11,1,1) }')

Calling Awk in a shell script

I have this command which executes correctly if run directly on the terminal.
awk '/word/ {print NR}' file.txt | head -n 1
The purpose is to find the line number of the line on which the word 'word' first appears in file.txt.
But when I put it in a script file, it doens't seem to work.
#! /bin/sh
if [ $# -ne 2 ]
then
echo "Usage: $0 <word> <filename>"
exit 1
fi
awk '/$1/ {print NR}' $2 | head -n 1
So what did I do wrong?
Thanks,
Replace the single quotes with double quotes so that the $1 is evaluated by the shell:
awk "/$1/ {print NR}" $2 | head -n 1
In the shell, single-quotes prevent parameter-substitution; so if your script is invoked like this:
script.sh word
then you want to run this AWK program:
/word/ {print NR}
but you're actually running this one:
/$1/ {print NR}
and needless to say, AWK has no idea what $1 is supposed to be.
To fix this, change your single-quotes to double-quotes:
awk "/$1/ {print NR}" $2 | head -n 1
so that the shell will substitute word for $1.
You should use AWK's variable passing feature:
awk -v patt="$1" '$0 ~ patt {print NR; exit}' "$2"
The exit makes the head -1 unnecessary.
you could also pass the value as a variable to awk:
awk -v varA=$1 '{if(match($0,varA)>0){print NR;}}' $2 | head -n 1
Seems more cumbersome than the above, but illustrates passing vars.

Pass variable to nawk in bash?

I'm trying to pass a variable to nawk in a bash script, but it's not actually printing the $commentValue variable's contents. Everything works great, except the last part of the printf statement. Thanks!
echo -n "Service Name: "
read serviceName
echo -n "Comment: "
read commentValue
for check in $(grep "CURRENT SERVICE STATE" $nagiosLog |grep -w "$serviceName" | nawk -F": " '{print $2}' |sort -u ) ; do
echo $check | nawk -F";" -v now=$now '{ printf( "[%u]=ACKNOWLEDGE_SVC_PROBLEM;"$1";"$2";2;1;0;admin;$commentValue"\n", now)}' >> $nagiosCommand
done
$commentValue is inside an invocation to nawk, so it is considered as a variable in nawk, not a variable in bash. Since you do not have such a variable in nawk, you won't get anything there. You should first pass the variable "inside" nawk using the -v switch just like you did for the now variable; i.e.:
... | nawk -F";" -v now=$now -v "commentValue=$commentValue"
Note the quotes - they are required in case $commentValue contains whitespace.

Resources