How to use ssh tail command and write to local file - linux

I'm trying to write a script that reads logs from 3 linux machines and writes the logs (with some kind of prefix) in one file.
My problem is that I can access to the file in order to see it, but when I try to write it doesn't work.
Working code
expect -c "
spawn ssh user#x.x.x.x \" tail -f my_file\"
expect {
\"*assword\" {send \"PASS\r\";}
}
expect eof
"
if I add
tail -f >> my_file.log
it doesn't work.

First off, I would highly recommend learning how to use SSH with keys so that you don't need a password.
Then, all you need to do is this:
ssh username#server 'tail -f filename' >> my_file.log

Your command
tail -f filename >> my_file.log
is being run on the remote. So my_file.log is on the remote. To get the output to a local file, move the >> my_file.log to the end of the expect script:
expect -c "..." >> my_file.log

Related

Bash for loops on a remote server

I am attempting to run multiple commands via a bash script on a remote server. specifically, the for loop to be run on the remote server is giving me issues. I suspect it is because I don't know how to properly escape characters or use $().
Below is the code.
ssh (user)#(server) <<EOF
sudo su - (username)
whoami
'for e in $(`ls -lrt /usr/jboss/jbosseap | awk '{print $9}' | grep multichannel`);
do
echo "$e";
done'
Removing user and server names for obvious reasons. Just concentrate on the for loop. when I run that for loop command line (without the $()) its works fine. Just not sure how to nest it in a remote call.
Thanks very much for any and all help!
If you've got a complex script that you're trying to run over ssh you're going to be better off putting that script in a file and piping that file into ssh like:
cat remote_script.sh | ssh user#host
or:
cat remote_script.sh | ssh user#host sudo -u username
And now you don't have to worry about N levels of escaping.
You can run it as below .
here file "list " includes your list of nodes and script should be present in all nodes
for i in $(cat list ) ;do ssh -o StrictHostKeyChecking=no $i "/path/your_script" ;done

SSH remote server - display only "echo" on output in terminal

I have bash script (for example):
ssh -t -t user#domain.com << EOF
cd /home/admin
mkdir test
echo 'Some text'
exit
EOF
Can I display only "echo" command in terminal? It is possible?
Now all commands are displayed.
Thank you
Specifying the commands on standard input with ssh -t causes the commands to be echoed back, but you don't have to do that.
ssh -t user#domain.com "
cd /home/admin
mkdir test
echo 'Some text'"
(The exit isn't really required or useful, so I left it out.)
Use single quotes if you want to prevent the local shell from interpolating variables etc in the string containing the commands.
To selectively display an individual command as well as its output, you can use something like
sh -vc 'echo \"Some text\"'
although the nested quoting can start getting on your nerves pretty quickly.

pseudo-terminal error will not be allocated because stdin is not a terminal - sudo

There are other threads with this same topic but my issue is unique. I am running a bash script that has a function that sshes to a remote server and runs a sudo command on the remote server. I'm using the ssh -t option to avoid the requiretty issue. The offending line of code works fine as long as it's NOT being called from within the while loop. The while loop basically reads from a csv file on the local server and calls the checkAuthType function:
while read inputline
do
ARRAY=(`echo $inputline | tr ',' ' '`)
HOSTNAME=${ARRAY[0]}
OS_TYPE=${ARRAY[1]}
checkAuthType $HOSTNAME $OS_TYPE
<more irrelevant code>
done < configfile.csv
This is the function that sits at the top of the script (outside of any while loops):
function checkAuthType()
{
if [ $2 == linux ]; then
LINE=`ssh -t $1 'sudo grep "PasswordAuthentication" /etc/ssh/sshd_config | grep -v "yes\|Yes\|#"'`
fi
if [ $2 == unix ]; then
LINE=`ssh -n $1 'grep "PasswordAuthentication" /usr/local/etc/sshd_config | grep -v "yes\|Yes\|#"'`
fi
<more irrelevant code>
}
So, the offending line is the line that has the sudo command within the function. I can change the command to something simple like "sudo ls -l" and I will still get the "stdin is not a terminal" error. I've also tried "ssh -t -t" but to no avail. But if I call the checkAuthType function from outside of the while loop, it works fine. What is it about the while loop that changes the terminal and how do I fix it? Thank you one thousand times in advance.
Another option to try to get around the problem would be to redirect the file to a different file descriptor and force read to read from it instead.
while read inputline <&3
do
ARRAY=(`echo $inputline | tr ',' ' '`)
HOSTNAME=${ARRAY[0]}
OS_TYPE=${ARRAY[1]}
checkAuthType $HOSTNAME $OS_TYPE
<more irrelevant code>
done 3< configfile.csv
I am guessing you are testing with linux. You should try add the -n flag to your (linux) ssh command to avoid having ssh read from stdin - as it normally reads from stdin the while loop is feeding it your csv.
UPDATE
You should (usually) use the -n flag when scripting with SSH, and the flag is typically needed for 'expected behavior' when using a while read-loop. It does not seem to be the main issue here, though.
There are probably other solutions to this, but you could try adding another -t flag to force pseudo-tty allocation when stdin is not a terminal:
ssh -n -t -t
BroSlow's approach with a different file descriptor seems to work! Since the read command reads from fd 3 and not stdin,
ssh and hence sudo still have or get a tty/pty as stdin.
# simple test case
while read line <&3; do
sudo -k
echo "$line"
ssh -t localhost 'sudo ls -ld /'
done 3<&- 3< <(echo 1; sleep 3; echo 2; sleep 3)

Shell script to compare remote directories

I have a shell script that I am using to compare directory contents. The script has to ssh to different servers to get a directory listing. When I run the script below, I am getting the contents of the server that I am logged into's /tmp directory listing and not that of the servers I am trying to ssh to. Could you please tell me what I am doing wrong?
The config file used in the script is as follows (called config.txt):
server1,server2,/tmp
The script is as follows
#!/bin/sh
CONFIGFILE="config.txt"
IFS=","
while read a b c
do
SERVER1=$a
SERVER2=$b
COMPDIR=$c
`ssh user#$SERVER1 'ls -l $COMPDIR'`| sed -n '1!p' >> server1.txt
`ssh user#$SERVER2 'ls -l $COMPDIR'`| sed -n '1!p' >> server2.txt
done < $CONFIGFILE
When I look at the outputs of server1.txt and server2.txt, they are both exactly the same - having the contents of /tmp of the server the script is running on (not server1 or 2). Doing the ssh +dir listing on command line works just fine. I am also getting the error "Pseudo-terminal will not be allocated because stdin is not a terminal". Adding the -t -t to the ssh command isnt helping either
Thank you
I have the back ticks in order to execute the command.
Backticks are not needed to execute a command - they are used to expand the standard output of the command into the command line. Certainly you don't want the output of your ssh commands to be interpreted as commands. Thus, it should work fine without the backticks:
ssh user#$SERVER1 "ls -l $COMPDIR" | sed -n '1!p' >>server1.txt
ssh user#$SERVER2 "ls -l $COMPDIR" | sed -n '1!p' >>server2.txt
(provided that double quotes to allow expansion of $COMPDIR are used).
first you need to generate keys to login to remote without keys
ssh-keygen -t rsa
ssh-copy-id -i ~/.ssh/id_rsa.pub remote-host
then try to ssh without pass
ssh remote-host
then try to invoke in your script but first make sanity check
var1=$(ssh remote-host) die "Cannot connect to remote host" unless $var1;

getting user input while SSH'ed into another box

I have a bash script that basically should work like below:
get build number from user and put it in buildNum var
prep the build on local machine by calling a local script with buildNum as it's argument
sftp the prepped zip file to remote server1
Do this:
ssh -v $server1 <<EOF
rm -rvf path1-on-remote-server1/*
cd path2-on-remote-server1
unzip ../prepped-zip-file-$buildNum.zip
exit
EOF
sftp the prepped zip file to remote server2
The problem i am having is that on the forth step of number 4, $buildNum is not known to the remote server and it fails.
I tried the following two solutions and both failed:
use double quotes "unzip ../prepped-zip-file-$buildNum.zip" which resulted in "unzip ../prepped-zip-file-11.6.zip: Command not found.
tried to get the build number again from the user during the SSH session which failed again by not even waiting for my input and looking for a zip file without the build number at the end of the name, as the var was empty,
i did :
ssh -v $server1 <<EOF
rm -rvf path1-on-remote-server1/*
cd path2-on-remote-server1
echo "enter build num once more: "
read bNum
unzip ../prepped-zip-file-$bNum.zip
exit
EOF
Any suggestions on how to achieve what i am after.
Thanks in advance
Are you sure this doesn't work?
ssh -v $server1 <<EOF
rm -rvf path1-on-remote-server1/*
cd path2-on-remote-server1
unzip ../prepped-zip-file-$buildNum.zip
exit
EOF
When I try it on my machine, with cat instead of ssh -v $server1 for testing, the variable does get substituted into the here-document, just as if the entire document had been on a command line. The remove shell never needs to know there was a variable in the first place.
Actually, though, you may want to give the remote command on the ssh command line rather than redirecting the standard input. This would be more robust in case some of the parts of it unexpectedly decide to try reading from stdin:
ssh -v $server1 "rm -rvf path1-on-remote-server1/*
cd path2-on-remote-server1
unzip ../prepped-zip-file-$buildNum.zip"
(Note that multi-line double-quoted strings are okay with bash).
#!/bin/sh
printf "Enter Build Number: "
read BUILD_NUM
cat << EOF | ssh $server1
hostname
echo "${BUILD_NUM}"
uptime
EOF
That works for me.

Resources