5

I have a couple of sub-folders mounted on /mnt. One is /mnt/data, and the other is /mnt/1804iso. The /data includes data folders and files mounted from another disk, and /1804iso includes a mounted ISO file whose contents I wanted to copy to folder /media/benny/0EB4-95E2/ which is a mounted flash-drive.

So I opened bash and typed sudo cp -Rn /mnt/1804iso/.* /media/benny/0EB4-95E2/. I would normally have omitted the period before wildcard asterisk /*/, but if I do that then a hidden file within the ISO does not copy over. So with this command one strange thing occurred. After copying over the ISO files correctly, then it started to copy over the /mnt/data folders and files as well. I cannot see why that can happen as there is no reference to that folder, unless my understanding of the command part /mnt/1804iso/.* is totally flawed.

Could someone kindly explain why my /mnt/data folder was included for copying?

Michael Homer
  • 76,565

2 Answers2

9

.* will expand to your hidden file, ., and ... This is an unfortunate part of how Bash filename expansion works: there is a directory entry called .., which consists of an initial . and then any number of characters after it, so it's matched by .* and included.

You can see this happen by running e.g.:

echo /mnt/1804iso/.*

which will list out /mnt/1804iso/. and /mnt/1804iso/.. along with the rest.

../data is your data directory. You will end up with a directory structure in the destination like this:

.hidden
xyz
data/
data/...
1804iso/.hidden
1804iso/xyz
...

That is, you'll actually end up with two copies of everything you wanted to copy, plus all that stuff you didn't. If you use cp -Rnv you'll see what it's copying and where to as it goes.

Some other shells will be nicer about this. In zsh, it would have done closer to what you want: only the hidden file would have been copied. In Bash, you could use cp src/.[^.]* dest to almost match the zsh behaviour, and list two source locations. Alternatively, you can run shopt -s dotglob beforehand, and then src/* will expand to include the dotfiles, but exclude the . and .. entries (but this may lead to doing things you didn't mean to later on, so be careful).


For what you actually wanted to do, I suggest using rsync instead:

rsync -avx /mnt/1804iso/ /media/benny/0EB4-95E2/

This will copy the contents of the 1804iso directory to the destination (note final slash!), including any hidden files.

Michael Homer
  • 76,565
  • 1
    I think I follow you. Because of my use of .*, I end up with an option of /mnt/1804iso/.. which is the equivalent of my parent folder /mnt in this case. So, not only does /mnt/1804iso/ get copied but everything else within /mnt Is that right? I think rsync is safer, but I tend to use that for back-ups ratrher than simple file/folder copying. – Paul Benson Feb 10 '19 at 21:06
  • Probably. It may depend a little on exactly how your cp implementation works (some will fail early and stop trying), but you've definitely asked it to copy 1804iso's parent directory recursively. – Michael Homer Feb 10 '19 at 21:09
  • Your bash example is not quite equivalent, since it would miss a file named ..foo – Nate Eldredge Feb 11 '19 at 01:14
  • @NateEldredge Good point! I... don't think that's worth fixing, but I'll note that it's not fully equivalent. – Michael Homer Feb 11 '19 at 01:16
  • I think .[^.]* ..?* would work. – Nate Eldredge Feb 11 '19 at 01:32
3

The pattern /mnt/1804iso/.* expands to, amongst possibly other things, the directory entry /mnt/1804iso/.., which is the same as /mnt. I'm geussing that's why it started copying /mnt/data.

In this case, I would just use rsync:

rsync -ai /mnt/1804iso/ /media/benny/0EB4-95E2

This would copy all of /mnt/1804iso, including hidden files, into /media/benny/0EB4-95E2. Leaving off the / at the end of the source directory would create a 1804iso directory below the target directory.

Alternatively, enable the dotglob shell option in bash with shopt -s dotglob to make * match hidden names as well as non-hidden names (but not . or ..). Then use

cp -Rn /mnt/1804iso/* /media/benny/0EB4-95E2/
Kusalananda
  • 333,661