9

Who can give me a logical explanation to this issue:

I can not run this command:

sudo cp /data/*20150522* /backup/

cp: cannot stat `/data/*20150522*': No such file or directory

And when i switch to root its working with no problem.

I'm sure it is about having the right privileges to list the files inside to /data directory which have the folowing access privileges:

drwxrwx--- 1 root root 

But here i'm running the command with sudo, so what is the problem here?

jxh
  • 333
Anis H
  • 201

1 Answers1

21

The shell attempts expansion of the glob pattern before it passes the expanded result to cp (actually, it is passing the result to sudo which then passes it unchanged to cp). Since the shell (it is running as you, not root) is not able to traverse the directory, cp ends up receiving the unexpanded pattern in its argument list.

cp does not perform any glob expansion itself. It expects a list of file names. The string with the pattern in it does not name a file.

Perhaps the most straight forward way to perform the task is to invoke your command in a sub-shell. Quote the command with either double quotes (") or single quotes (').

sudo sh -c "cp /data/*20150522* /backup/"
sudo sh -c 'cp /data/*20150522* /backup/'

This works because the sub-shell expands the glob pattern in the command string before invoking the command. Since the sub-shell is running as root under sudo, the expansion is successful.

Using double quotes to quote the command to the sub-shell allows the parent shell to expand shell variables before invoking the sudo command. If you want variables to be expanded by the sub-shell, the single quotes should be used instead. In this case, it is equivalent, since you do not have any variables. But, you could add one to see the difference in behavior.

sudo sh -c "echo $USER; cp /data/*20150522* /backup/"
sudo sh -c 'echo $USER; cp /data/*20150522* /backup/'

The first command will display your user name, while the second command will display the root user name.

jxh
  • 333
  • 1
    Can this behaviour be worked around somehow? sudo <something> with wildcards expansion with raised privileges. – Eugene Sh. May 22 '15 at 16:52
  • 1
    Maybe something like this sudo bash -c 'cp /data/*foo* /dest' instead? – Zoredache May 22 '15 at 17:23
  • @Zoredache: I had just thought of that before reading your comment. Thanks. – jxh May 22 '15 at 17:29
  • I think you are wrong with the " vs '. None of them will expand the *, the difference is in the expansion of shell variables (try with "$UID" and '$UID'). – rodrigo May 22 '15 at 19:29
  • @rodrigo: You are correct, I have updated the answer. I knew about the shell variable expansion, but for some reason I expected that to hold for glob expansion as well. – jxh May 22 '15 at 21:04