Bash script for scp interpreting tilde (~) too soon

bashhomequotingscpshell-script

So, I just started a new C++ class that requires me to program in a Linux environment. I don't have Linux installed on my machine, but I do have OS X and I can ssh into a linux machine in the lab at school (and this is preferable since my code must compile and run on the lab machine regardless of whether or not it works on my machine). If you can't tell by the end of this question, I am not incredibly familiar with Linux.

I will frequently need to take files that I download onto my local machine and put them on the remote machine, edit them to make the program, and then put them back onto my local machine to upload them to our dropbox. I got tired of typing
scp -P xx user@remote.host.com:~/filename filename
and decided to make an alias to do this. That's when I discovered aliases don't handle this kind of thing, so I decided to write a shell script instead. Here's what I've got:

#!/bin/bash

# Author: me
# Created 26 August 2014
# transfers a file from remote machine to current directory in local machine
# keeps same filename

location="$1"
# name gets just the part of the path after the last slash
# ie the filename
name="$(echo "$1" | sed -n -e 's/^.*\///p')"
# echo "$location"
# echo "$name"
scp -P xx user@remote.host.com:"$location" "$name"

Theoretically, I can just type get ~/path/to/filename and it will get the file from the remote host and copy it (with the same filename) into the current directory on the local machine.

That scp command, if run from the command line, works great. When I stick it in a shell script, it breaks. It gives me the error: No such file or directory

After a lot of testing (you can see some commented out debugging output up there) and researching, I found that the shell is expanding ~ before it sends it to the script (well, this is my guess based on what I found out about globs). My script is then looking for the file in the path of my local machine's home folder instead of the remote machine's home folder. How do I make it stop doing that?

I realized while typing this question that I probably just need some quotes when I run the command… but I really don't want to do that. Can I fix this somehow without having to type get "~/filename" because having to type those quotes is really annoying.

Sorry if there's a lot of extraneous info but I figured too much is better than too little. Thanks!

PS: I already found this about configuring ssh. While useful, I would still have to type the exact filename twice, which does not allow me to be as lazy as I want to be.

Best Answer

By default, scp remote paths are interpreted relative to the home directory, so you don't need the ~ at all:

scp user@remote.host.com:some/file/name filename

will download some/file/name from the home directory of user and save it as filename locally. When you want to use an absolute file path on the remote server, start it with /: scp host:/etc/passwd passwd.

Strictly, it's possible that your server is interpreting things differently. In that case, you could put ~ into your script, rather than repeating it on the command line every time (be as lazy as you want to be!):

scp user@remote.host.com:~/"$location" "$name"

That way your shell never gets the chance to interpret it. (It's also possible to quote the ~ on the command line: \~ or '~', but that's more work than necessary.) I imagine the first approach above will work, though.


Another note on the name variable. You say you want it to be just the base filename. There is a command for that exact purpose, the basename command:

name="$(basename "$location")"

That's simpler than running everything through sed.

Related Question