59

Often I face this situation: I sshed into a remote server and ran some programs, and I want to copy their output files back to my local machine. What I do is remember the file path on remote machine, exit the connection, then scp user@remote:filepath .

Obviously this is not optimal. What I'm looking for is a way to let me scp file back to local machine without exiting the connection. I did some searching, almost all results are telling me how to do scp from my local machine, which I already know.

Is this possible? Better still, is it possible without needing to know the IP address of my local machine?

Mark Amery
  • 143,130
  • 81
  • 406
  • 459
laike9m
  • 18,344
  • 20
  • 107
  • 140
  • Why don't you open another terminal and from this terminal launch your `scp` command while your `ssh` connection is still opened in another terminal? You can open as many connection as you want to the same remote machine through ssh. – GHugo Aug 25 '14 at 08:49
  • you can : `echo $(pwd)/*something` to have a full path list of the files to copy. Then you suspend the ssh connection with `[ctrl]+[z]`, returning to your original prompt, where you type the `scp`, then resume the ssh session with `fg` to put it back running in the foreground – Olivier Dulac Aug 25 '14 at 09:41

4 Answers4

56

Given that you have an sshd running on your local machine, it's possible and you don't need to know your outgoing IP address. If SSH port forwarding is enabled, you can open a secure tunnel even when you already have an ssh connection opened, and without terminating it.

Assume you have an ssh connection to some server:

local $ ssh user@example.com
Password:
remote $ echo abc > abc.txt  # now we have a file here

OK now we need to copy that file back to our local server, and for some reason we don't want to open a new connection. OK, let's get the ssh command line by pressing Enter ~C (Enter, then tilde, then capital C):

ssh> help
Commands:
      -L[bind_address:]port:host:hostport    Request local forward
      -R[bind_address:]port:host:hostport    Request remote forward
      -D[bind_address:]port                  Request dynamic forward
      -KR[bind_address:]port                 Cancel remote forward

That's just like the regular -L/R/D options. We'll need -R, so we hit Enter ~C again and type:

ssh> -R 127.0.0.1:2222:127.0.0.1:22
Forwarding port.

Here we forward remote server's port 2222 to local machine's port 22 (and here is where you need the local SSH server to be started on port 22; if it's listening on some other port, use it instead of 22).

Now just run scp on a remote server and copy our file to remote server's port 2222 which is mapped to our local machine's port 22 (where our local sshd is running).

remote $ scp -P2222 abc.txt user@127.0.0.1:
user@127.0.0.1's password:
abc.txt                   100%    4     0.0KB/s   00:00

We are done!

remote $ exit
logout
Connection to example.com closed.
local $ cat abc.txt
abc

Tricky, but if you really cannot just run scp from another terminal, could help.

afenster
  • 3,468
  • 19
  • 26
  • 3
    Can the flag `-R 127.0.0.1:2222:127.0.0.1:22` be issued when **starting** the SSH session? So I can add to my `.bashrc` the alias `alias ssh="ssh -R 127.0.0.1:2222:127.0.0.1:22"` on my local machine, and then write a bash function in the `.bashrc` of the remote machine whose contents look something like `scp -P2222 $1 user@127.0.0.1:$2`? That would make scp'ing from the remote machine very efficient. OP's motivation for this is mainly that scp'ing inside the local machine means I can't use tab completion on the file and must supply the entire pathname. – Luke Davis Jul 26 '17 at 04:06
  • 2
    @LukeDavis Yes, you can add this option to your ssh command line. I guess OP's question was related to a situation where no special arrangements were made before making a connection. – afenster Jul 30 '17 at 11:06
  • One more question: the `2222` and `22` were examples right? So I could, for example, make the remote/local port numbers both `999`? – Luke Davis Dec 19 '17 at 18:09
  • @LukeDavis sure you can. 22 is the default port for sshd but your service can be configured to listen to any port. – afenster Dec 21 '17 at 00:28
  • 4
    This is awesome. But as someone who got here because he was looking for a simple way to do something without having to open another tab and do a new scp connection, this solution is very hilarious. – deweydb Jun 05 '20 at 21:55
  • This post would be more useful if you explained how to know what ports to use. – Eric Hansen Jun 30 '21 at 19:51
  • Thank you. This is brilliant. I now really got my head around working with ssh forwarding. Excellent demonstration in minimal words. – taiyodayo Nov 30 '21 at 04:28
  • I have an error : `connect to host 127.0.0.1 port 2222: Connection refused` – kio21 Dec 29 '21 at 07:39
  • Just for clarification, it seems like this requires 2 connections to remote. Running the command to forward port on remote blocks my user input so I'd have to open a new remote tab to run the scp command. Is this correct? – Connor Jan 13 '22 at 19:08
4

I found this one-liner solution on SU to be a lot more straightforward than the accepted answer. Since it uses an environmental variable for the local IP address, I think that it also satisfies the OP's request to not know it in advance.

based on that, here's a bash function to "DownLoad" a file (i.e. push from SSH session to a set location on the local machine)

function dl(){
    scp "$1" ${SSH_CLIENT%% *}:/home/<USER>/Downloads
}

Now I can just call dl somefile.txt while SSH'd into the remote and somefile.txt appears in my local Downloads folder.

extras:

  • I use rsa keys (ssh-copy-id) to get around password prompt
  • I found this trick to prevent the local bashrc from being sourced on the scp call

Note: this requires SSH access to local machine from remote (is this often the case for anyone?)

Alex Shroyer
  • 3,499
  • 2
  • 28
  • 54
brotherJ4mes
  • 159
  • 1
  • 5
  • 1
    For me I found the environment variable was `SSH_CLIENT`, not `CLIENT_IP`; I am running macOS sshing into Ubuntu. OTOH, I wasn't able to get past my NAT without reconfiguring so I didn't find it worth the trouble to figure out and went another way. Still, maybe knowing that it might be `SSH_CLIENT` instead of `CLIENT_IP` will help someone else. – MikeSchinkel Jun 08 '22 at 08:54
  • 1
    @MikeSchinkel I have the same setup (macOS local, Ubuntu remote) and can confirm that CLIENT_IP is not set but SSH_CLIENT is set on the remote. I edited the answer accordingly. – Alex Shroyer Sep 21 '22 at 15:17
  • 1
    Thanks! (you're right) I thought that I had edited/responded before but apparently not. – brotherJ4mes Sep 22 '22 at 16:28
1

The other answers are pretty good and most users should be able to work with them. However, I found the accepted answer a tad cumbersome and others not flexible enough. A VPN server in between was also causing trouble for me with figuring out IP addresses.

So, the workaround I use is to generate the required scp command on the remote system using the following function in my .bashrc file:

function getCopyCommand {
  echo "scp user@remote:$(pwd)/$1 ."
}

I find rsync to be more useful if the local system is almost a mirror of the remote server (including the username) and I require to copy the directory structure also.

function getCopyCommand {
  echo "rsync -rvPR user@remote:$(pwd)/$1 /"
}

The generated scp or rsync command is then simply pasted on my local terminal to retrieve the file.

Cibin Joseph
  • 1,173
  • 1
  • 11
  • 16
0

You would need a local ssh server running in your machine, then you can just:

    scp [-r] local_content your_local_user@your_local_machine_ip:

Anyway, you don't need to close your remote connection to make a remote copy, just open another terminal and run scp there.

Javier S.
  • 24
  • 3