I have the following excerpt from a perl script to automate an FTP session, I'm hoping someone can explain how it works.
system("rsh some_server ftp -in ftp.something.com << !
user anonymous someone\#somewhere.org
some ftp commands
bye");
The background. This perl script runs on a Linux machine, it remotes into a Solaris machine. The FTP session must be executed from the Solaris machine because the FTP site performs IP address checking.
Formerly this script ran on the Solaris machine directly (i.e. it didn't use rsh) I hacked it around and came up with this which seems to work. However I have little idea how, in particular I don't understand the << ! bit at the end of the first line. It looks a little like a here-document but I'm not really sure.
Any explanations welcome.
You are right, << is a heredoc, which is made clear by the following warning (which I get when I take out the rsh command):
sh: line 2: warning: here-document at line 0 delimited by end-of-file (wanted `!')
The construct
<< HEREDOC
reads as standard input everything from HEREDOC up to a line containing only HEREDOC or up to an end-of-file character. When you put this after a command, it is equivalent to
command < file
where file contains the text in the heredoc. In your case, instead of HEREDOC the delimiter is !, so the ! is not passed to ftp but everything after ! is. This is equivalent to
$ cat file
user anonymous someone\#somewhere.org
some ftp commands
bye
$ ftp -in ftp.something.com < file
rsh takes that entire command and runs it on your remote host.
As illustrated by user1146334's answer, this command does not act on the principal of least surprise. At the very least, make it less confusing by changing it to
system("rsh some_server ftp -in ftp.something.com << HEREDOC
user anonymous someone\#somewhere.org
some ftp commands
bye
HEREDOC");
Or even better, as mpapec mentioned in the comments, use Net::FTP and Net::SSH2.
Did you look at the man page?
-i Turns off interactive prompting during multiple file transfers.
-n Restrains ftp from attempting “auto-login” upon initial connection. If auto-login is enabled, ftp will check the .netrc (see netrc(5)) file in the user's
home directory for an entry describing an account on the remote machine. If no entry exists, ftp will prompt for the remote machine login name (default is
the user identity on the local machine), and, if necessary, prompt for a password and an account with which to login.
The client host and an optional port number with which ftp is to communicate may be specified on the command line. If this is done, ftp will immediately attempt
to establish a connection to an FTP server on that host; otherwise, ftp will enter its command interpreter and await instructions from the user. When ftp is
awaiting commands from the user the prompt ‘ftp>’ is provided to the user. The following commands are recognized by ftp:
! [command [args]]
Invoke an interactive shell on the local machine. If there are arguments, the first is taken to be a command to execute directly, with the rest of
the arguments as its arguments.
So essentially you're ftp'ing in and providing a new command per line in-line instead of from a file.
Related
I am having a strange issue. I have written a script which is basically running a perl script in remote server using ssh.
This script is working fine but after completion of the above operation it will ask user to choose the next operation.
it is showing the options in the command prompt but while I am giving any input it is not showing in the screen even after hitting enter also it remain same.
I am not getting what is the exact issue, but it seems there is some issue with the ssh command because if I am commenting out the ssh command it is working fine.
OPERATION:
print "1: run the script in remote server \n2: Exit\n\nEnter your choice:";
my $input=<STDIN>;
chomp($input);
..........
sub run_script()
{
my $com="sshg3.exe server -q --user=user --password=pass -exec script >/dev/null";
system("$com");
goto OPERATION;
}
after completing this ssh script it is showing in screen:
1: run remote script
2: exit
Enter your choice:
but while I am giving any input it is not displaying in the screen until and unless I am exiting it using crtl C.
Please can anyone help what might be the issue here ?
One of the classic gotchas with ssh is this - that it normally runs interactively, and as such will attach STDIN by default.
This can result in STDIN being consumed by ssh rather than your script.
Try it with ssh -n instead.
You can redirect the output in command prompt if -n option is not available for you.
try this one it might work for you.
system("$com />null");
As per https://support.ssh.com/manuals/client-user/62/sshg3.html there is an option for redirecting input use --dev-null (*nix) or --null (Windows).
-n, --dev-null (Unix), -n, --null (Windows)
Redirects input from /dev/null (Unix) and from NUL (Windows).
Is it possible to run perl script, which is located on a remote server, on that server from Windows? There is a job on a remote server that I want to get done every time I make something on Windows.
You have to have something listening for an instruction to run the script, and then you have to send the instruction.
There are lots of approaches you could take to that, including:
Running an SSH server and then connecting to it from an ssh client on the windows machine
Running an HTTP server, running the script through FastCGI, and then requesting the URL for it from curl or a browser on the Windows machine
Writing a custom protocol, listening on a socket, and then writing a custom client that you run on the Windows machine
Absolutely.
You can use plink to run commands on the server from Windows, assuming the server is running sshd.
plink user#a.domain.ext echo hi
This will print "hi\n" to the standard output.
Substitute /path/to/perl/script for echo above and substitute hi with any command line argument that the script needs.
plink is available here: http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html
One cautionary personal note from doing this many times is that the environment in which the perl script will be run is much less complete than what you would experience when logging in via a full SSH session and running the command interactively. Many environment variables you would normally expect are unset.
For instance using "set | wc -l" in the command above produces only 39 environment variables defined, but from an interactive SSH session, there are 57 environment variables defined. You have to make sure your perl script isn't depending on an environment variable that hasn't been set. For instance, you may need to use full paths for any modules that it uses, or by using the -I flag in the shebang line, because #INC may not be what you expect it to be.
I have a perl script where I need to connect to another machine using ssh and there run another perl script. I tried using this line:
system("ssh $admin_server 'perl /Perl/scripts/capture_server_restarts_gse.pl $month $date'");
But everytime the script gets to that line, I get the prompt for the remote machine and the script doesn't run.
How can I fix this so the script runs automatically on the other machine without showing the prompt.
Note: I don't need the password and user to connect to the remote machine we already solved that.
Why not copy your public key onto the other machine ? That way you'll be pre-authorised.
Here are the instructions on how to do this using ssh-keygen
Otherwise you have to feed ssh with your password, and that's tricky since ssh normally takes input from a tty and you have to configure your script with the password.
The SSH server may be configured to run always some custom shell instead of the command passed from the client.
Try just running some simple command from the command line, i.e.:
ssh server ls
A less likely possibility is that the perl variables interpolated into the system argument could contain some shell metacharacters requiring better escaping. For instance, a semicolon inside $admin_server.
I want to run a Perl script in a remote machine using telnet or ssh. The script is on my local host.how can do this. Can anyone please help me on this?
If you for some reason don't want to copy the script to the remote host and then run it, you can send the script to the Perl interpreter over stdin. If perl doesn't get either a script name of a script on the command line it tries to read the script on stdin. So this would work:
ssh user#remote perl < my_script.pl
Of course this requires that all necessary modules are already installed on the remote host. If you script only have pure perl dependencies you can work around this restriction by using App::FatPacker to make your script (more) self contained.
But if this is an recurring task I would recommend getting the script deployed correctly to your remote host.
scp your script to remote machine.
ssh user#remote 'perl /path/to/remote/script.pl'
Using HERE document across SSH might also do the trick you are after. You can run at least a BASH script without first separately copying it to remote. I have not verified anything else than BASH but no reason to doubt either. Please see:
ssh + here document + interactive mode
Is it possible to have a Perl script run shell aliases? I am running into a situation where we've got a Perl module I don't have access to modify and one of the things it does is logs into multiple servers via SSH to run some commands remotely. Sadly some of the systems (which I also don't have access to modify) have a buggy SSH server that will disconnect as soon as my system tries to send an SSH public key. I have the SSH agent running because I need it to connect to some other servers.
My initial solution was to set up an alias to set ssh to ssh -o PubkeyAuthentication=no, but Perl runs the ssh binary it finds in the PATH instead of trying to use the alias.
It looks like the only solutions are disable the SSH agent while I am connecting to the problem servers or override the Perl module that does the actual connection.
Perhaps you could put a command called ssh in PATH ahead of the ssh which runs ssh as you want it to be run.
Alter the PATH before you run the perl script, or use this in your .ssh/config
Host *
PubkeyAuthentication no
Why don't you skip the alias and just create a shell script called ssh in a directory somewhere, then change the path to put that directory before the one containing the real ssh?
I had to do this recently with iostat because the new version output a different format that a third-party product couldn't handle (it scanned the output to generate a report).
I just created an iostat shell script which called the real iostat (with hardcoded path, but you could be more sophisticated), passing the output through an awk script to massage it into the original format. Then, I changed the path for the third-party program and it started working fine.
You could declare a function in .bashrc (or .profile or whatever) with that name. It could look like this (might break):
function ssh {
/usr/bin/ssh -o PubkeyAuthentication=no "$#"
}
But using a config file might be the best solution in your case.