2

Under the current directory I have a number of files, and one directory. I would like to move all files to the sub directory:

mv ./* subdir/
cannot move ./subdir to a subdirectory of itself...

The warning is harmless but it makes mv return 1, therefore it's not possible to determine whether other files have been moved.

cp could help but I have some large files to move and it's not efficient enough.

Scripting would seem to work too, but I'd prefer a one liner if there is any.

5
  • 1
    If you're happy to use bash, you can turn on extglob (shopt -s extglob) and use mv ./!(subdir) subdir/
    – camh
    Jun 30, 2015 at 7:56
  • thanks for closing a question which deverses an answer different from the "duplicate". go ahead and delete this question so that other users will never find an answer here.
    – Howard
    Jul 1, 2015 at 5:17
  • is this what unix.se has become? over-moderation without careful consideration? I think I should stop contributing here.
    – Howard
    Jul 1, 2015 at 5:25
  • 2
    Do the answers on the other question not solve this problem? They seem perfect. Having good answers here isn't a reason not to close as a duplicate, we can always merge them Jul 1, 2015 at 5:47
  • @Howard I don't understand. What's the problem here? The questions are clearly duplicates. That doesn't mean that this question is "useless". Dupes are good, they act as signposts and help people find the answer they are looking for. Please don't deface your posts.
    – terdon
    Jul 1, 2015 at 8:34

2 Answers 2

1

You can do it with find:

$ find -maxdepth 1 -not -name subdir -print0 | xargs -0 mv -t subdir

Where:

  • -maxdepth 1 restricts the find traversal to the current directory (not a POSIX option, but e.g. available in GNU find)
  • -print0 tells find to terminate lines with 0 bytes - thus, making the command work with unusual filenames (e.g. ones containing newlines), also not POSIX, but provided by e.g. GNU find
  • -0 tells xargs about the 0 bytes - again, not POSIX, but e.g. understood by e.g. GNU xargs
  • -t instructs mv that the first argument is the target (not the last) - this is ideal for this use case - like before, option is not in POSIX, but e.g. implemented by GNU mv
0

You can try yet another more concise form, just like this one:

mv `ls -A |grep -v <subdir>` <subdir>

Here backslash characters stand for command substitution, i.e. mv will be executed with an output from command placed into backslashes as part of its arguments.

2
  • This has multiple issues: It does not work with filenames that contain whitespace. The grep pattern 'subdir' is expanded by the shell and thus breaks when there are multiple directories/files matching it. The last 'subdir' also potentially matches more files/directories than just 'subdir'. The command breaks when the current working directory contains many files such that the argument vector limit is reached. Jun 30, 2015 at 11:44
  • @maxschlepzig thanks for the note, I have slightly corrected formatting Jul 1, 2015 at 19:26

Not the answer you're looking for? Browse other questions tagged .