0

I have seen that to copy or move directory contents, including hidden files and folders in this directory, to another one, some people use the "mysterious" (DN) thing.

cp -R dir1/*(DN) dir2/
mv dir/*(DN) dir2/

It seems man cp and man mv don't mention it. What is it, and where can I read more about it?

Kusalananda
  • 333,661
jsx97
  • 181
  • 1
    When you say "I have seen" or similar, you need to say where you have seen something. Context is important; seeing the original source allows for trying to figure out what they might have meant, or indeed if the source is even something worth reading for anyone... Perhaps the source would even contain a hint as to where to look for the meaning of those mysterious characters. (Which would be the zsh shell, not cp or mv themselves.) – ilkkachu Mar 10 '24 at 21:03
  • @ilkkachu It was here: https://unix.stackexchange.com/q/6393 – jsx97 Mar 10 '24 at 21:29

1 Answers1

4

They are zsh Glob Qualifiers

   N      sets the NULL_GLOB option for the current pattern

D sets the GLOB_DOTS option for the current pattern

where the meanings are

  NULL_GLOB (-G)
          If  a pattern for filename generation has no matches, delete the
          pattern from the argument list instead of  reporting  an  error.
          Overrides NOMATCH.
   GLOB_DOTS (-4)
          Do not require a leading `.' in a filename to be matched explic‐
          itly.

You can find more information in the zsh expansion manual page, man zshexpn and in the zsh options manual page man zshoptions.

In your:

cp -R dir1/*(DN) dir2/

That means that the hidden files are also copied, but the N qualifier doesn't make much sense here, as that means that if there's no matching file (if dir1 is empty or not readable), then the command will become:

cp -R dir2/

And while N suppresses the no match error by zsh, you'll still get a (more confusing) missing destination file operand error by cp.

N (nullglob) is most useful in things like files=( *(N) ) or for file in *(N)... when it's OK to have an empty expansion.

But in your case, it's better to leave it out.

Alternatively, if you wanted cp not to be run when there's no match but without reporting an error, you could do:

function { (( $# == 0 )) || cp -R -- "$@" dir2/; } dir1/*(ND)

Where the generated list (allowed to be empty) is passed to an anonymous function which checks its size before calling cp.

steeldriver
  • 81,074