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.
Related
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
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.
I've been trying for a couple nights to get this Script to run with no luck. I'm trying to write a script using Bash that allows a user to paste a block of text, and the script will grep out the valid IP addresses from the text, and automatically ping them in order.
So far, after much modification, I'm stuck at this point:
#!/bin/sh
echo Paste Text with IP Addresses
read inputtext
echo "$inputtext">inputtext.txt
grep -E -o "([0-9]{1,3}[\.]){3}[0-9]{1,3}" inputtext.txt > address.txt
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
rm inputtext.txt
rm address.txt
After running this script, the user is prompted as desired, and if an IP address was included in the first line of text, the ping check will succeed, but then all the text after that line will be spat out onto the following command prompt. So it seems that my issue lies in when I read from user input. The only part that is being read is the first line, and once a break is encountered, the script does not considered any lines past the first in its work.
As written, you just need an outer loop to actually read each line of user input.
#!/bin/sh
echo Paste Text with IP Addresses
while read -r inputtext
do
echo "$inputtext">inputtext.txt
grep -E -o "([0-9]{1,3}[\.]){3}[0-9]{1,3}" inputtext.txt > address.txt
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
rm inputtext.txt
rm address.txt
done
However, you can actually simplify this much further and eliminate the temporary files.
#!/bin/sh
echo Paste Text with IP Addresses
while read -r inputtext
do
ip=$(echo "$inputtext" | grep -E -o "([0-9]{1,3}[\.]){3}[0-9]{1,3}" | awk '{print $1}')
if ping -c1 $ip >/dev/null 2>&1; then
echo $ip IS UP
else
echo $ip IS DOWN
fi
done
Script read file line by line and check folders on remote server using command ls
But my do-while - is work only 1 time, and ; for example: if try use rsync - all fine, while work correct, problem only with ssh user#server ls $SERVER_FOLDER >> $LOG
i try use incorrect syntax?
Error from console: syntax error near unexpected token 'done'
LOG="/path_to_log/log.txt"
FILE="/path_to_file/projects_id.txt"
cat $FILE | while read -r line || [[ -n $line ]]
do
ID=$(echo $line | cut -d' ' -f3)
SERVER_FOLDER=`echo "/path_to_id/$ID/"`
echo "SERVER_FOLDER:" $SERVER_FOLDER
ssh user#server ls $SERVER_FOLDER >> $LOG
sleep 20
done
Add the -n option to ssh to prevent it from reading stdin. What is happening is that ssh is consuming all the input from the file (that is coming through stdin), so the while loop terminates after the first line because there is nothing left for it to read.
Change your code to:
while read -r line || [[ -n $line ]]
do
ID=$(cut -d' ' -f3 <<< "$line")
SERVER_FOLDER="/path_to_id/$ID/"
echo "SERVER_FOLDER: $SERVER_FOLDER"
ssh -n user#server ls $SERVER_FOLDER >> $LOG
sleep 20
done < "$FILE"
I have also made some other improvements such as changing the way you are reading the file (cat is not necessary).
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