7

I apologize that this seems like such a dumb question, but I can't afford to screw it up.

I have a bunch of folders like so:

/users/me/foo/oops1

/users/me/foo/oops2

/users/me/foo/oops3

/users/me/foo/oops4

/users/me/foo/bar

Unfortunately, they aren't uniformly named like that, and there are hundreds of oops folders.

I intended to copy all the oops folders into bar. Is there an easy way to move all the oops folders into bar that won't result in some kind of recursive move problem?

It took several hours to copy the files. I'm hoping that the move will be much faster.

This is on a redhat linux server by the way. I only have ssh access.

I think if I do

cd foo
mv * bar

there will be a problem.

jgritty
  • 301
  • 3
  • 9

5 Answers5

7

What you're proposing is exactly right. mv is smart enough and will say this:

mv: cannot move `bar' to a subdirectory of itself, `bar/bar'

However, all your oopsx dirs will be inside bar.

Perleone
  • 260
3

Yes, you're right, that would be a problem because * will also match bar; you can't mv directory into itself.

The techy way is to use command substitution and a loop to mv only the things that aren't bar. For example, in bash, you could write something like this, but note that it will fail if it hits a name that contains a space (because command substitution breaks things into words at spaces.)

mv $(for i in *; do if [ $i != "bar" ]; then echo $i; fi; done) bar

But honestly, I'm lazy. I would mv bar out of the way, then mv everything into it, then move it back. You're only moving filesystem links, not file contents, so it's fast. This also has the advantage of working if you have names with spaces.

cd foo
mv bar ../bar.save
mv * ../bar.save
mv ../bar.save bar
3

Unfortunately, Matt's answer and Nicole's answer both exhibit bad style and will break if any of the folders even contains a single whitespace character, globbing character (like *) or a newline. Running for item in $(ls …) is a huge mistake one can make because it will bite them sooner or later, and iterating over filenames, not outputting them properly can cause all sorts of troubles.

Never parse the output of ls.

There's a tool in Linux for finding files matching certain criteria, and it's called find:

find . -mindepth 1 -maxdepth 1 \
-type d ! -regex ".\/bar$" \
-exec mv '{}' ./bar/ \;

This will move any directories in the current working directory which aren't called bar into ./bar/. It will work even if the directory names contain spaces, globbing characters or newlines.

The regular expression .\/bar$ will match only the directory called ./bar, and it's negated by !.

slhck
  • 235,242
1

If if makes you feel safer, you could do this in BASH:

for item in `ls -d | grep -v "^bar$"`; do mv $item bar; done;
Matt
  • 27
-1

cd into foo

mv -t bar oops[[:digit:]]

of the more general

mv -t bar oops*
WikiWitz
  • 1,291