20

If I do a sudo cp /etc/foo.txt ~/foo.txt, the new file is created with root as the owner.

Right now, I see no way around this other than using the last two commands (ls to clarify use-case):

belmin@server1$ ls /etc/foo.txt
>  -rw------- 1 root root 3848 Mar  6 20:35 /etc/foo.txt
>
belmin@server1$ sudo cp /etc/foo.txt ~/foo.txt
belmin@server1$ sudo chown belmin: $_

I would prefer:

  1. Doing it in one sudo command.
  2. Not having to specify my current user (maybe using a variable?).
1
  • sudo cat /etc/foo.txt > ~/foo.txt. Files tend to be only readable by root for a reason, so remember to keep that reason in mind when making copies readable by non-root users.
    – jw013
    Aug 20, 2014 at 13:24

5 Answers 5

32

Use install instead of cp:

sudo install -o belmin /etc/foo.txt ~/foo.txt
2
  • Wasn't aware of install. Thank you. Aug 20, 2014 at 14:13
  • 4
    @BelminFernandez: In order to accommodate your second preference: sudo install -o "$USER" /etc/foo.txt ~/foo.txt Aug 20, 2014 at 22:05
14

With a POSIX-compatible cp you can sudo cp -p foo bar to preserve the following file metadata when copying:

  • Access time
  • Modification time
  • User ID
  • Group ID
  • Mode

If you want to set a different user JennyD's solution is best.

5
  • 2
    That only works when the original file is owned by the target user.
    – Jenny D
    Aug 20, 2014 at 13:09
  • 4
    I presume the person running sudo doesn't own the original file, otherwise they wouldn't need to use sudo. Aug 20, 2014 at 13:09
  • @EightBitTony You don't need sudo to copy a file you don't own. You just need read access, after all.
    – l0b0
    Aug 20, 2014 at 16:17
  • Yes, mistype on my part - but I assume the user ID in question can't read the file either, because they still wouldn't need sudo. So we have to assume the user ID intended to own the final file has no access to the original file. Either way, this isn't a sudo 'problem'. Your answer suggests preserving an owner that we have to assume isn't desired. Aug 20, 2014 at 17:39
  • 2
    It's theoretically possible that the file is owned by the target user but is located in a directory which the target user doesn't have permission to enter. But it's not very likely :-)
    – Jenny D
    Aug 21, 2014 at 5:59
8

If you do:

sudo cat /etc/foo.txt > ~/foo.txt

Then ~/foo.txt will be open by the shell as you (so created with your credentials), and then sudo will be executed with its stdout redirected to that.

In the end, the file will be owned by you.

That kind of approach also helps limiting the things done by root. Here, root only uses his privilege to open /etc/foo.txt, it doesn't do the thing that is potentially harmful (open a file for writing, that could have bad consequences if ~/foo.txt was a symlink for instance).

1
  • 2
    This assumes the user can write to the target directory.
    – Johan
    Aug 27, 2014 at 9:07
3

Using sudo, you switch to another user. That's the whole point of the command. I assume you don't have any regular access to the first file, so you need to be another user (root in this case) to gain access.

There's no way for sudo itself to manage that, since all sudo is doing is switching you to the other user to execute the command.

You will need to

  1. keep using two commands (or one compound command)
  2. find another command (such as install, seen in another answer)
  3. or write a script and execute that script via sudo.
1

Sudo creates an environment variable "SUDO_USER" that you can use to find out the user who logged in (actually who ran Sudo).

Assuming you Sudo to root (it is possible to use Sudo to access other users too), you can write a script to automate the following two steps.

cp source target
chown $SUDO_USER target

(This won't work if you sudo to a non root user since only root can give away files.)

Automating it will be a bit of work. If source is a single file and target is not a directory, then your work is done. I assume that you asked the question because the problem is only a real issue in more complex situations, eg when doing something like:

cp /path/source/some*files /path/target/directory/

A complex script to figure out what files and what directories are passed, which ones were pre-existing, which ones were actually overwritten, and to change the ownership of only the successfully copied files could be written.

This work has already been done. You can use cpio - After sudo to root, use cpio to copy the files. cpio needs a list of the files to copy so it is a two step process. Below I use ls to generate the list of files to copy.

ls /path/source/some*files | cpio -pdm --owner $SUDO_USER /path/target/directory/

The -pdm means "Passthrough mode, Create directories as needed, Maintain file modification times"

--owner $SUDO_USER" causes the specified user to own the files.

The final operand is the directory where cpio must store the files.

To learn more about cpio awesomeness, go to the CPIO manual page here

Doing this in a single sudo command is also possible. Assuming that your user have rights to access the files, use sudo only for the cpio portion, like this:

ls /path/source/some*files | cpio -pdm --owner $USER /path/target/directory/

In the above case I'm using $USER in stead of $SUDO_USER because it is evaluated before Sudo runs. Alternatively, if the user doesn't have access to list the files, put it in a wrapper script and use sudo to run the wrapper. This can become harder, but in the simplest case The wrapper takes two arguments, a source and a target.

This goes into the "cp_as_user" wrapper:

ls $1 | cpio -pdm --owner $SUDO_USER $2

Then use the wrapper like this:

sudo cp_as_user "/path/to/some*files" /path/to/target/directory

You must log in to answer this question.

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