Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

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.

share|improve this question
    
Then what are they named? Do you want to move everything in foo besides bar into bar? –  cpast Jan 19 '13 at 23:02
    
Correct. They have various names. –  jgritty Jan 19 '13 at 23:04

5 Answers 5

up vote 2 down vote accepted

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;
share|improve this answer
2  
What about accidentally matching barf, barfly or bark? Use grep -v '^bar$' to just match "bar". –  Perleone Jan 19 '13 at 22:41
1  
Agree. Better with "^bar$". Thanks for noticing. I have updated the answer. –  Matt Jan 19 '13 at 22:45
1  
Running ls -d only gives you ., the current working directory. Are you sure this works? Have you tried the command? See: How to list folders using bash commands? — furthermore this script will fail if any of the directories contains a space, newline or globbing character in their name. –  slhck Jan 20 '13 at 10:56
    
-1: As pointed out by @slhck, this answer doesn't work. And @Perleone's answer is better. –  Adrian Pronk Jan 26 '13 at 10:12

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.

share|improve this answer

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

share|improve this answer
    
But this also very slow because it runs mv once for every file. And with so many terms, it presents a lot of opportunities to make a mistake. bash needs and lacks a better substitution facility that can deal with filenames with spaces. –  Nicole Hamilton Jan 20 '13 at 16:17
    
Yes, it runs mv once for every folder, not file. I believe with \+ it should run faster and move all folders in one command, although I don't know if that'd cause a major speedup. I agree with you that this should be way easier, because when dealing with files in Bash the simplest way to do things is never the correct way, unfortunately. I just felt there needed to be an answer that would work in any case. –  slhck Jan 20 '13 at 16:19
    
Luckily, none of the files have * or space, but this does seem like a better answer in general. –  jgritty Jan 20 '13 at 17:49

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
share|improve this answer
    
Your script doesn't work if any of the directories contains a space, globbing character or newline. For example, a directory called "foo baz" would appear as mv foo baz bar, and subsequently fail. –  slhck Jan 20 '13 at 10:50
    
Yes, yes, I notice you always point that out. You must have that on a macro key. But (a) if you have spaces in the names, you probably know that, (b) this is a problem with bash that should be fixed (it is fixed in my C shell), (c) this is a good reason for doing it the second way, which is what I actually recommended. –  Nicole Hamilton Jan 20 '13 at 15:52
    
There are probably hundreds of bash scripts on Super User alone that show these trivial defects. This is a site where we should learn people how to achieve something and adapt it to their needs. From the experience of the OP I wouldn't say that they know having a space in the first place is a problem. At least you should explicitly mention such assumptions in your answer (I'd also remove the downvote then). So maybe you could edit your post to clarify that. Also, it's not a problem of the shell per se, it's just a problem when the wrong approach is used. –  slhck Jan 20 '13 at 15:56
    
I've also talked to seasoned users on Unix & Linux, where the policy on "broken" bash scripts is the same. Edit to improve or downvote/comment to point out deficiencies. Please don't take it personally—we're not that many users here who post answers with shell scripts. I just happened to notice it. –  slhck Jan 20 '13 at 15:58
1  
While it is true that * will match bar, it is not a problem since 'mv'/the kernel is smart enough to detect this instance. So rather than stating is it is a problem, it is a good way to do it (unless you want to filter out certain directories, but that's a different question) –  JvO Jan 21 '13 at 0:45

cd into foo

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

of the more general

mv -t bar oops*
share|improve this answer
    
haha sorry for typo –  WikiWitz Jan 19 '13 at 22:35
2  
They aren't really called oops though. –  jgritty Jan 19 '13 at 22:37

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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