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.