How to copy hidden files and hidden subdirectories (the ones starting with a dot) in folder A to folder B? For example if I have this structure:

A/a
A/b
A/.a
A/.b/
A/.b/somefile
A/.b/.c

I would like to copy to B just the hidden files and hidden subdirectories in A:

B/.a
B/.b/
B/.b/somefile
B/.b/.c

I have already tried this command: cp A/.* B from this other superuser question. However, it does not copy the subdirectories. Also tried cp -r A/.* B, but it copies . so I end with an exact copy of A (including the normal files). Any help is appreciated.

up vote 10 down vote accepted

As long as you're only looking for hidden files and folders at the level of A and don't want, for example

A/b/.hidden

to be copied, you should be able to use this:

cp -r A/.[^.]* B

It basically means copy anything that starts with a . and then any character other than a . That filters out . and ..

Edit: Removed the -p from the cp command since Asker hasn't indicated he wants to preserve any ownerships, dates, etc.

  • This works for the example file and directory names given in the question, but the text of the question says “hidden files and hidden subdirectories (the ones starting with a dot)”, and this answer will not find files and directories whose names begin with two dots; e.g., ..c. – Scott Oct 27 '14 at 22:27
  • That's quite an edge case, but a legitimate concern none-the-less. I hadn't considered that. You could account for that by switching to .*[^.] but then you'd miss files that end with a .. I think you would indeed need extended globbing to truly account for all cases. – Omnipresence Oct 28 '14 at 13:08

The problem with A/.* is that there is the directory . in A which also matches the pattern.

You can turn on extended glob patterns and use the following:

shopt -s extglob
cp -r A/.!(?(.)) B    

It matches files whose name starts with a dot and whose second character is neither a dot nor nothing ( ?(.) matches nothing or a dot, !(...) negates it, i.e. !(?(.)) matches everything else than nothing or a dot).

  • +1 for a correct answer. Note that .!(@(|.)) is (AFAICT) equivalent to the above, (IMNSHO) a little clearer, and only one character longer. – Scott Oct 27 '14 at 22:28

For cases like this would recommend using find instead of cp like this:

find A/ -type f -maxdepth 1 -name '.*' -exec cp -p {} B/ \;

The basic syntax breaks down like this: find items in the directory A/ whose type is a file (instead of a directory) and do this for a maxdepth of 1 directories and whose name begins with .. And once these files are found, exec the cp command with a -p flag to preserve dates/times from the source ({}) to the destination of B/.

I like using maxdepth to add a layer of control so I am not accidentally copying a whole filesystem. But feel free to remove that.

  • Not sure about how this addresses copying just hidden files? – gaboroncancio Oct 23 '14 at 14:29
  • @gaboroncancio It does now. Check my edit for the -name '.*' addition. – JakeGould Oct 23 '14 at 14:30
  • 1
    This is a very good answer. However, the question says “hidden files and hidden subdirectories” – so why are you saying -type f? Also, I suspect that you meant cp -r rather than cp -p. Also, you could streamline this a little by changing the end to -exec cp -rt B {} +, specifying the copy target (-t) before the source files, so you don’t need to fire off a separate cp process for every file and directory that you want to copy. – Scott Oct 27 '14 at 22:37
  • @Scott Thanks, Scott! I admit this could be improved & appreciate your input. I learn something new every day doing this work! – JakeGould Oct 27 '14 at 23:56
 for item in `find A -type d | grep -E "\."` ; do cp -r $item B ; done
  • find A -type d provides a recursive list within A with only directories
  • grep -E "\." filters directories with a dot (i.e.: hidden directories)
  • the -E option was needed here because without it it means "current directory" as well
  • the backslash is to avoid the meaning, under regexp, of "any character"
  • cp -r to copy recursively

I have created the files and folders structure for A and executed the command in Git Bash (I'm not with a linux just right now) and it worked.

  • This breaks if files have whitespace or special characters in their name or path. – slhck Oct 23 '14 at 16:30
  • Thanks for noticing :) Actually I limitied to the "test case" by @gaboroncancio. If you can give me other test battery I may try to improve that (of course if you want, improve it by yourself either editing this response or creating a new answer) – malarres Oct 24 '14 at 10:39
  • You could simply put the dotfiles in a folder called A B, and then it'd act unexpectedly because it'd expand to cp -r A B/.dotfile B. The general advice is not to parse find or ls output at all. If you use find you should also use its own options for filtering rather than grep, and if you pipe find output somewhere else, use -print0, or directly call the command you want. See the find manual. – slhck Oct 24 '14 at 10:45
  • Even more generally, when working with files it's safest to use shell globs as explained in other answers (although they often require extglob to be set). – slhck Oct 24 '14 at 10:46
  • Thanks for the link. Let's leave the find parsing then. – malarres Oct 27 '14 at 7:22

As an alternative you can use this other command if the second character is alphanumeric (source):

cp -r A/.[a-zA-Z0-9]* B
  • This works for the example file and directory names given in the question, but the text of the question says “hidden files and hidden subdirectories (the ones starting with a dot)”, and this answer will not find files and directories whose names begin with a dot and a special character; e.g., .@foo or ..c. – Scott Oct 27 '14 at 22:29
  • That is why I point that it works if the second character is alphanumeric. ;) – gaboroncancio Oct 27 '14 at 22:41

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.