16

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.

5 Answers5

24

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.

5

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).

choroba
  • 20,299
5

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 A/ -type f: find items in the directory A/ whose type is a file (instead of a directory)…
  • -maxdepth 1 -name '.*': To this for a maxdepth of 1 directories and whose name begins with ..
  • -exec cp -p {} B/ \;: 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.

Giacomo1968
  • 58,727
0
 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.

Jan Doggen
  • 4,657
malarres
  • 208
0

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

cp -r A/.[a-zA-Z0-9]* B