27

I'm trying to copy all files that do not begin with the letter "a", in ksh.

Copying from the source machine to destination machine is working fine:

scp -p !(a*) user@machine:/path/directory/.

But, if I am on the destination server and want to copy from the source server, is failing:

scp -p user@machine:/path/!(a*) .

Any ideas?

4 Answers 4

43

I agree with vonbrand. Globing is handled by the shell you're running in. So scp user@machine:/path/* will expand /path/* to the files in the LOCAL /path/*, not on the remote machine.

However, just for grins I tried:

scp "user@machine:/path/[regex here]" .  

and .... it worked. Try that. Note the quotes. Very necessary. Let us know.

Note: the user account on the remote machine may default to a different shell program than yours, so the rules of wild card expansion may be different, so 'ware that.

2
  • Saved my time. Thanks a lot. Aug 2, 2020 at 18:14
  • The pattern user@machine:/path/* will not expand /path/* locally, it will expand user@machine:/path/* (the whole thing) locally. That means all files in the directory path under the directory user@machine:, in the current directory.
    – Kusalananda
    Apr 27, 2022 at 6:22
5

Remote names passed to scp are actually interpreted as a whitespace-separated list of patterns on the remote side. This is often an annoyance when you try to copy a file whose name contains spaces, but here it's useful: scp -p 'user@machine:/path/a*' . would copy all files whose name begins with a.

Your command will work if you quote the pattern so that it's interpreted remotely rather than locally, provided you pass another hurdle. The pattern !(a*) is not a basic shell pattern, it's a ksh extension (that bash and zsh also support if you set the appropriate option). So this will only work if your remote shell is ksh, not if it's some other shell and you exec ksh from .profile or something similar.

The easy way, unless you're in some kind of restricted or antique environment, is to forget about scp. You'd like remote files to work just like local files, so make them local files: mount the remote directory with sshfs. This requires FUSE on the local machine and an SFTP server (i.e. an sftp-server executable that sshd launches) on the remote machine.

mkdir ~/net/machine
sshfs user@machine:/ ~/net/machine
cp -p ~/net/machine/path/!(a*) .
1
  • "Remote names passed to scp are actually interpreted as a whitespace-separated list of patterns on the remote side." -- Worse, they form a tail of some remote command, a shell command. scp 'router:nonexistent; beep' whatever makes my router beep because the command is ... nonexistent; beep. If one doesn't know what happens under the hood (researched here), how and what and when to quote for the remote shell, then scp is potentially harmful in general. "Forget about scp" is the best advice here. +1 Apr 27, 2022 at 6:31
2

This isn't "scp with regular expressions", the one handling the file globs is the shell. scp just gets handed the already expanded list of files. And the expansion happens on the machine where the command is run.

0
1

What I found was that on older HP-UX machines (parisc 11.11), I had to use [^a]* But, on newer machines (parisc 11.31 and newer) it works with !(a*)

This is what I ended up with. And it works:

    if [[  ${S_MACH} = "phd026a" || ${S_MACH} = "tht030a" ]]
    then
            scp -p -r ${S_MACH}:${S_DIR}/bin/[^a^b^c^p]* ${D_DIR}/bin/.
    else
            scp -p -r ${S_MACH}:${S_DIR}/bin/!((a*)|(b*)|(c*)|(p*)) ${D_DIR}/bin/.
    fi
1
  • Both solutions work for me on an 11.11 server.
    – user14755
    Sep 30, 2015 at 0:03

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .