Skip to main content copying all file : r/linuxquestions

copying all file

Hey,

I wanted to copy all all files from one directory to another, like this:

cp -i /source/. /destination

I knew the source had no subdirectories and I wanted a prompt if files needed to be overwritten.

Now, this didnt work got the error " -r not specified, omitting directory /source/"

It worked with -r. I dont understand why though, there wre

Cheers,

Archived post. New comments cannot be posted and votes cannot be cast.
Some cars don’t know how to match your energy. Couldn't be the all-new Acura ADX though.¯\_(ツ)_/¯
Thumbnail image: Some cars don’t know how to match your energy. Couldn't be the all-new Acura ADX though.¯\_(ツ)_/¯
Sort by:
Q&A (Default)
Open comment sort options

I'm not sure if you're looking for a better way to do this, or just an explanation about why it doesn't work.

A simple way to accomplish what you want is to use * instead of .. At the end of your source directory.

cp -i /source/* /destination

As for why you're seeing the behavior you're seeing... Hopefully someone can help clear this up for me, because I got a bit confused while looking into it.

The simple explanation would be that . represents a directory, and cp will not copy any directories without the -r option. That being said, cp doesn't really seem to handle it as a directory. This seems to be because the trailing . character isn't expanded by the shell, and is instead interpreted by cp internally.

The way cp handles it is... weird. It seems like kind of a special case. Practically it can be used to specify hidden files in a recursive copy.

cp -r /source/. /destination will copy all files in the source directory including hidden files. cp -r /source/* /destination will copy all files in the source directory excluding hidden files. In both cases the directory itself isn't copied, just the contents.

In the example above the . does not seem to represent a directory. It behaves more like a special wildcard character that includes hidden files. That would indicate that cp doesn't consider it a directory, and so -r should not be required... I don't really understand WHY it behaves that way and I can't seem to find any good explanation for it anywhere.

So good question. I'm stumped. Hopefully someone else can elaborate.

Edited
Profile Badge for the Achievement Top 1% Commenter Top 1% Commenter

In the example above the . does not seem to represent a directory.

No, it behaves exactly like any other directory.

Let's say you had these files:

/source/dir/a
/source/dir/b
/source/dir/.hidden

and you wanted to copy these into the directory:

/destination

If you ran:

cp -r /source/dir /destination

cp would:

  • Recognise that /source/dir is a directory and create the corresponding /destination/dir directory, if it does not already exist.

  • Copy the a, b and .hidden files into this /destination/dir directory.

Now replace dir with .:

cp -r /source/. /destination

Now cp would:

  • Recognise that /source/. is a directory and create the corresponding /destination/. directory, if it does not already exist.

  • Copy the a, b and .hidden files into this /destination/. directory.

The key here is that the first step wouldn't actually create a new directory, since /destination/. does already exist. The end result is that a, b and .hidden would appear inside /destination.


Edit: If you want to use cp to safely recursively copy directories, a better way (at least with GNU cp) is:

cp -rT /source/ /destination/

The -T option (aka --no-target-directory) ensures that the command will work correctly even if the /destination directory does not exist. The trailing slash on /source/ ensures that the command will fail if for some reason the source is not a directory, and the trailing slash on /destination/ is effectively irrelevant (but I like it for symmetry).

More replies
More replies

It is early and with one eye open look into “rsync”.

there's another way around, if you want to omit -r:

shopt -s dotglobs

this will set the * to also match all dotfiles and dotdirs except '.' and '..' untill you log out

cp dir/* /path/to/dest/

Rsync is just what u need