SSH command within a script terminates prematurely - shell

From myhost.mydomain.com, I start a nc listener. Then login to another host to start a netcat push to my host:
nc -l 9999 > data.gz &
ssh repo.mydomain.com "cat /path/to/file.gz | nc myhost.mydomain.com 9999"
These two commands are part of a script. Only 32K bytes are sent to the host and the ssh command terminates, the nc listener gets an EOF and it terminates as well.
When I run the ssh command on the command line (i.e. not as part of the script) on myhost.mydomain.com the complete file is downloaded. What's going on?

I think there is something else that happens in your script which causes this effect. For example, if you run the second command in the background as well and terminate the script, your OS might kill the background commands during script cleanup.
Also look for set -o pipebreak which terminates all the commands in a pipeline when one of them returns with != 0.
On a second note, the approach looks overly complex to me. Try to reduce it to
ssh repo.mydomain.com "cat /path/to/file.gz" > data.gz
(ssh connects stdout of the remote with the local). It's more clear when you write it like this:
ssh > data.gz repo.mydomain.com "cat /path/to/file.gz"
That way, you can get rid of nc. As far as I know, nc is synchronous, so the second invocation (which sends the data) should only return after all the data has been sent and flushed.

Related

Redirect ssh output to file while performing other commands

I'm looking for some help with a script of mine. I'm new at bash scripting and I'm trying to start a service on a remote host with ssh and then capture all the output of this service to a file in my local host. The problem is that I also want to execute other commands after this one:
ssh $remotehost "./server $port" > logFile &
ssh $remotehost "nc -q 2 localhost $port < $payload"
Now, the first command starts an HTTP server that simply prints out any request that it receives, while the second command sends a request to such server.
Normally, if I were to execute the two commands on two separate shells I would get the first response on the terminal, but now I need it on the file.
I would like to have the server output all the requests on the log file, keeping a sort of open ssh connection to receive any new output of the server process.
I hope I made myself clear.
thank you for your help!
EDIT: Here's the output of the first command:
(Output is empty in the terminal... it waits for requests).
As you can see the commands doesn't return anything yet but it waits.
When I execute the second command on a new terminal (the request), the output of the first terminal is the following:
The request is displayed.
Now I would like to execute both commands in sequence in a bash script, sending the output of the first terminal (which is null until the second command is run) to a file so that ANY output, triggered by later issued requests, is sent to a file.
EDIT2: As of now, with the commands above, the server answers any requests but the output is not registered in the log file.

Why does ack over ssh not work?

I've got a simple bash script to remove some folders on a remote server over ssh. It basically does this:
THE_HOST=12.34.56.78
ssh me#$THE_HOST "rm /the/file/path/thefile.zip"
This works perfectly well. Before I do this I often search the contents of the files in a folder for a string using ack:
ack thestring /the/folder/path/
This works perfect when I ssh into the server and run it, but when I use it in one command it doesn't work:
ssh me#$THE_HOST "ack thestring /the/folder/path/"
This seems to freeze or run forever: I get no output and the command never ends. Does anybody know why this doesn't work for ack?
Could be ack behaves differently when it is run in a terminal. Try using the -t argument
ssh -t me#$THE_HOST "ack thestring /the/folder/path/"
When ack detects that stdin is not a terminal(a tty device), it will attempt to read the text to search in from stdin instead of the given file/folder. That's what happens when you run it through ssh, stdin will be connected to the ssh connection, which does not look like a terminal(tty) to ack.
The -t argument to ssh instead allocates a tty and connects it to stdin/out of the program you run, ack will then think it runs in a terminal and instead use the file/folder argument for searching.
See http://github.com/beyondgrep/ack2/issues/659

prevent output from script in xinetd service

I have a bash script that starts Xvnc after doing some other processing, and it's launched from a xinetd service. However the script indirectly outputs some text to stdout and stderr, which gets sent back to the connecting client.
Is there some way to tell xinetd to ignore any ouput from the script and just let Xvnc take over the connection?
(I assume Xvnc somehow takes over the socket from xinetd, rather than just using stdout to communicate with xinetd?)
Put the following lines into the script at the beginning:
exec >/dev/null
exec 2>/dev/null

How to connect stdin of a list of commands (with pipes) to one of those commands

I need to give the user ability to send/receive messages over the network (using netcat) while the connection is stablished (the user, in this case, is using nc as client). The problem is that I need to send a line before user starts interacting. My first attempt was:
echo 'my first line' | nc server port
The problem with this approach is that nc closes the connection when echo finishes its execution, so the user can't send commands via stdin because the shell is given back to him (and also the answer from server is not received because it delays some seconds to start answering and, as nc closes the connection, the answer is never received by the user).
I also tried grouping commands:
{ echo 'my first line'; cat -; } | nc server port
It works almost the way I need, but if server closes the connection, it will wait until I press <ENTER> to give me the shell again. I need to get the shell back when the server closes the connection (in this case, the client - my nc command - will never closes the connection, except if I press Ctrl+C).
I also tried named pipes, without success.
Do you have any tip on how to do it?
Note: I'm using openbsd-netcat.
You probably want to look into expect(1).
It is cat that wait for the 'enter'.
You may write a script execute after nc to kill the cat and it will return to shell automatically.
You can try this to see if it works for you.
perl -e "\$|=1;print \"my first line\\n\" ; while (<STDIN>) {print;}" | nc server port
This one should produce the behaviour you want:
echo "Here is your MOTD." | nc server port ; nc server port
I would suggest you use cat << EOF, but I think it will not work as you expect.
I don't know how you can send EOF when the connection is closed.

Script: SSH command execute and leave shell open, pipe output to file

I would like to execute a ssh command and pipe the output to a file.
In general I would do:
ssh user#ip "command" >> /myfile
the problem is that ssh close the connection once the command is executed, however - my command sends the output to the ssh channel via another programm in the background, therefore I am not receiving the output.
How can I treat ssh to leave my shell open?
cheers
sven
My understanding is that command starts some background process that perhaps will write some output to the terminal later. If command terminates before that the ssh session will be terminated and there will be no terminal for the background program to write to.
One simple and naive solution is to just sleep long enough
ssh user#ip "command; sleep 30m" >> /myfile
A better solution than sleep would be to wait for the background process(es) to finish in some more intelligent way, but that is impossible to say without further details.
Something more powerful than bash would be Python with Paramiko and PyExpect.

Resources