Bash + SSH + Grep not generating output - bash

I'm trying to use the script below to extract values from the df command on remote servers, then record to a log file. SSH keys are in place and no password is needed (this is not the problem).
It's getting hung up, however, and not spitting back output.
#!/bin/bash
PATH=/bin:/usr/bin:/usr/sbin
export PATH
SERVERLIST=/opt/scripts/server-list.dat
while IFS='|' read -u 3 hostname; do
echo evaluating $hostname...
SIZE=$(ssh $hostname | df -Pkhl | grep '/Volumes/UserStorage$' | awk '{print $2}')
echo $SIZE
done 3< $SERVERLIST
exit 0

You need to run df on the remote system, not pipe the output of an interactive ssh to it:
SIZE=$(ssh -n $hostname df -Pkhl | grep '/Volumes/UserStorage$' | awk '{print $2}')
Also, use the -n option to ssh to keep it from trying to read from stdin, which would consume the rest of the lines from the server list file.

Related

Loop EOF ssh -n can't create file

Hope this time it's not a duplicate. I didn't find anything.
My code:
#!/bin/bash
FILE=/home/user/srv.txt
TICKET=task
while read LINE; do
ssh -nT $LINE << 'EOF'
touch info.txt
hostname >> info.txt
ifconfig | grep inet | awk '$3 ~ "cast" {print $2}' >> info.txt
grep -i ^server /etc/zabbix/zabbix_agentd.conf >> info.txt
echo "- Done -" >> info.txt
EOF
ssh -nT $LINE "cat info.txt" >> $TICKET.txt
done < $FILE #End
My issue:
if I only use ssh $LINE it will only ssh to the host on the first line and also display an error Pseudo-terminal will not be allocated because stdin is not a terminal.
using ssh -T , fix the error message above and it will create the file info.txt
using ssh -nT , fix the error where ssh only read the first line but I get an error message cat: info.txt: No such file or directory. If I ssh to the hosts, I can confirm that there is no info.txt file in my home folder. and with ssh -T, I have this file in my home folder.
I tried with the option -t, also HERE, EOF without ' ... ' but no luck
Do I miss something?
Thanks for your help,
Iswaren
You have two problems.
If you invoke ssh without -n it may consume the $FILE input (it drains its stdin)
If you invoke ssh with -n it won't read its stdin, so none of the commands will be executed
However, the first ssh has had its input redirected to come from a heredoc, so it does not need -n.
As stated in the comments, the second ssh call is not needed. Rather than piping into info.txt and then copying that into a local file, just output to the local file directly:
while read LINE; do
ssh -T $LINE >>$TICKET.txt <<'EOF'
hostname
ifconfig | grep inet | awk '$3 ~ "cast" {print $2}'
grep -i ^server /etc/zabbix/zabbix_agentd.conf
echo "- Done -"
EOF
done <$FILE

List all cronjobs if there are any without superfluous info

Trying to output a list of cronjobs, not a list of users. The raw output of crontab -l is way too dirty and I can't seem to clean it up. I run this with sudo script.sh or su and then run it. I've tried invoking it sudo script.sh | grep -v no also. I'm mystified why this doesn't work:
#!/bin/bash
#Trying to show all cronjobs but no extraneous info
#
# This shows "no crontab for USER" for every USER without
# a crontab - I only want to see actual cronjobs, not a long
# list of users without crontabs
echo "Here is the basic output that needs manipulation:
"
for USER in `cat /etc/passwd | cut -d":" -f1`; do
crontab -l -u $USER
done
#
# grep -v fails me
# (grep'ing the output of the script as a whole fails also)
echo "
trying with grep -v no on each line:
"
for USER in `cat /etc/passwd | cut -d":" -f1`; do
crontab -l -u $USER | grep -v no
done
echo "
maybe with quotes around the no:
"
for USER in `cat /etc/passwd | cut -d":" -f1`; do
crontab -l -u $USER | grep -v "no"
done
# string manipulation - I can't even get started
echo "
And here I try to put the commmand output into a string so I can manipulate it further, and use an if/then/fi on the product:
"
for USER in `cat /etc/passwd | cut -d":" -f1`; do
STRING="$(crontab -l -u $USER | grep -v no)"
echo "STRING: $STRING"
done
BTW, is there an easier way to get code to format correctly here than pasting in 4 spaces at the beginning of each line? I must have experimented for 40 minutes. Not complaining, just asking.
crontab is wiring the "no crontab for user" to standard error. To get rid of those messages, you can run
crontab -l -u $USER 2>/dev/null
within your loop.
I would also suggest renaming USER into something else. The USER variable name is reserved, and should be set to your user (login) name. Generally, you should use lower case variable names, to avoid this sort of name clash.

SSH in a script - commands not running on remote server [duplicate]

This question already has answers here:
Execute a command on remote hosts via ssh from inside a bash script
(4 answers)
Closed 7 years ago.
I need a help with a bash script that connect to server as root, execute some commands and then exit from the server.
I tried this script but when login login to server performed the command not running !
#!/bin/bash
sudo ssh -o ConnectTimeout=10 $1 'exit'
if [ $? != 0 ]; then
echo "Could not connect to $1 , script stopped"
exit
fi
sudo ssh $1
echo "SRV=`cat /etc/puppet/puppet.conf | grep -i srv_domain | awk '{print $3}'`"
echo $SRV
echo "puppetMaster=`host -t srv _x-puppet._tcp.$SRV | head -1 | awk '{print $8}' | cut -f1 -d"."`"
echo $puppetMaster
'exit'
I'm surprised nobody has suggested a heredoc yet.
sudo ssh "$1" <<'EOF'
SRV=`cat /etc/puppet/puppet.conf | grep -i srv_domain | awk '{print $3}'`
echo $SRV
echo "puppetMaster=`host -t srv _x-puppet._tcp.$SRV | head -1 | awk '{print $8}' | cut -f1 -d"."`"
echo $puppetMaster
EOF
This feeds everything from the <<'EOF' until the line starting with EOF into the stdin of ssh, to be received and run by the remote shell.
The commands following ssh machine in a script are not run on the machine. They will be run on the local machine once the ssh exits.
Either specify the commands to run as an argument of ssh, or alternatively, run ssh and make it read the commands from standard input, and send the commands to it.
ssh machine ls
# or
echo ls | ssh machine
You seem to be a little confused as to what runs where.
ssh -o ConnectTimeout=10 $1 'exit'
will connect to $1, run exit, and disconnect.
ssh -o ConnectTimeout=10 $1 'echo hello world'
will print hello world on
the server and then disconnect.
ssh $1
will open up a shell on the remote. After the shell has ended, the following commands will run locally.
echo "SRV=`cat /etc/puppet/puppet.conf | grep -i srv_domain | awk '{print $3}'`"
echo $SRV
echo "puppetMaster=`host -t srv _x-puppet._tcp.$SRV | head -1 | awk '{print $8}' | cut -f1 -d"."`"
echo $puppetMaster
'exit'
What you probably want is start bash on the remote and forward to it the commands you want to give it via stdin.
echo "my commands" | ssh $1 bash
Technically, you don't need that bash -- ssh will start bash even without it (but with different rc files).

bash script to read/ping a list of ip addresses from a text file and then write the results to another file?

I have a text file with a lists of IP addresses called address.txt which contains the following
172.26.26.1 wlan01
172.26.27.65 wlan02
172.26.28.180 wlan03
I need to write a bash script that reads the only IP addresses, ping them and output to a another text file to something like this:
172.26.26.1 IS UP
172.26.27.65 IS DOWN
172.26.28.180 IS DOWN
I am fairly new to bash scripting so I am not sure where to start with this. Any help would be much appreciated.
In Linux this would work:
awk '{print $1}' < address.txt | while read ip; do ping -c1 $ip >/dev/null 2>&1 && echo $ip IS UP || echo $ip IS DOWN; done
I don't have a cygwin now to test, but it should work there too.
Explanation:
With awk we get the first column from the input file and pipe it into a loop
We send a single ping to $ip, and redirect standard output and standard error to /dev/null so it doesn't pollute our output
If ping is successful, the command after && is executed: echo $ip IS UP
If ping fails, the command after || is executed: echo $ip IS DOWN
Somewhat more readable, expanded format, to put in a script:
#!/bin/sh
awk '{print $1}' < address.txt | while read ip; do
if ping -c1 $ip >/dev/null 2>&1; then
echo $ip IS UP
else
echo $ip IS DOWN
fi
done

Bash script only read the first line of the file

I wrote a script to ssh to remote server to find the disk usage of a user. However, this script can only read the first line, it doesn't continue on the other lines of the file. Anything wrong with my script? Thanks.
#!/bin/bash
FILE="myfile.txt"
while read line; do
server=`echo $line|awk '{print $1}'`
cpid=`echo $line|awk '{print $2}'`
echo $server "---" $cpid "---" `ssh $server grep $cpid /var/cpanel/repquota.cache|awk '{print int($3/1000) "MB"}'`
done < $FILE
myfile.txt contents:
server1 user1
server2 user2
server3 user3
The ssh call is inheriting its standard input from the while loop, which redirects from your file. This causes the ssh command to consume the rest of the file. You'll need to use a different file descriptor to supply the read command:
#!/bin/bash
FILE="myfile.txt"
while read -u 3 server cpid; do
printf "$server---$cpid---"
ssh $server "grep $cpid /var/cpanel/repquota.cache | awk '{print int($3/1000) \"MB\"}'"
done 3< $FILE
An alternative is to explicitly redirect input to ssh from /dev/null, since you're not using it anyway.
#!/bin/bash
FILE="myfile.txt"
while read server cpid; do
printf "$server---$cpid---"
< /dev/null ssh $server "grep $cpid /var/cpanel/repquota.cache | awk '{print int($3/1000) \"MB\"}'"
done < $FILE
First of all you can simplify your read loop to
while read server cpid; do
echo $server "---" $cpid "---" `ssh ...`
done <$FILE
and save the parsing with awk. Another simplification is to save the call to grep and let awk do the search for $cpid
ssh $server "awk '/$cpid/ {print int(\$3/1000) \"MB\"}' /var/cpanel/repquota.cache"
To your problem, I guess the ssh call doesn't return, because it waits for a password or something, and so prevents the loop to continue.

Resources