LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (https://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   move all files in current directory into a subdirectory in the current directory (https://www.linuxquestions.org/questions/linux-newbie-8/move-all-files-in-current-directory-into-a-subdirectory-in-the-current-directory-637150/)

jakykong 04-22-2008 07:18 PM

move all files in current directory into a subdirectory in the current directory
 
What I came up with so far is:
find * .* -maxdepth 0 -path ./new-folder -prune -path ../ -prune -o -exec mv \{\} new-folder \;

Which is intended to move all files and folders, including those beginning with .'s, to the folder new-folder, created in the current directory. Mv alone won't work, because it can't move recursively and doesn't have an option to exclude the new-folder folder from the files it moves.

This *does* work. However, it's really messy, and produces some (seemingly harmless) error messages (although it exits with status 0 on my machine).

Does anyone know of a cleaner way to do this?

bgoodr 04-23-2008 12:28 AM

Use the -maxdepth 1 option to find, instead of the "*" and ".*", something like this:

Code:

mkdir ./dest_dir
find . -maxdepth 1 | grep -v dest_dir | xargs -i mv {} ./dest_dir

bgoodr

konsolebox 04-23-2008 02:45 AM

here's a function i wrote.. i think it's not yet the simplest but i hope it works properly:
Code:

moveallto() {
        local DESTDIR=${1}
        mkdir -p ${DESTDIR}
        find -type d -not -name ${DESTDIR} -not -path "./${DESTDIR}/*" -exec mkdir -p "${DESTDIR}/{}" \;
        find -type f -not -name ${DESTDIR} -not -path "./${DESTDIR}/*" -exec mv '{}' "${DESTDIR}/{}" \;
        find -maxdepth 1 -type d -not -name . -not -name ${DESTDIR} -exec rm -fr {} \;
}


jakykong 04-29-2008 06:04 PM

Quote:

Originally Posted by bgoodr (Post 3129889)
Use the -maxdepth 1 option to find, instead of the "*" and ".*", something like this:

Code:

mkdir ./dest_dir
find . -maxdepth 1 | grep -v dest_dir | xargs -i mv {} ./dest_dir

bgoodr

I hadn't considered using xargs... Using

find . -maxdepth 1 -exec mv '{}' dest_dir \;

causes an error when find finds the destination directory and tries to move it into itself.

That's definitely a lot easier to read.

Thanks!

bgoodr 04-30-2008 09:58 AM

Quote:

Originally Posted by jakykong (Post 3137128)
I hadn't considered using xargs... <snip> 1That's definitely a lot easier to read.

I don't know if it's any easier, my example command is a bit more verbose. However, what I find myself doing a lot is using echo to see what xargs is doing before committing myself to it. So first I add in the echo like this:
Code:

find . -maxdepth 1 | grep -v dest_dir | xargs -i echo mv {} ./dest_dir
The above won't actually mv any files, but will echo out the commands. You can either straight away feed the output to sh like this:
Code:

find . -maxdepth 1 | grep -v dest_dir | xargs -i echo mv {} ./dest_dir | sh -x
(I tacked on the -x to the sh so that I can see each command run such that I can see the command interspersed with any errors that occur in the move). But that isn't very useful in and of itself, but what is useful is maybe doing some sed in between the xargs and the sh.

Oh don't get me started (too late!). Let me warn you about "bad" characters in file names: I have a lot of mp3 files with characters such as spaces, single- and double-quotes. I often want to feed them to tools such as id3v2 to canonicalize the tags. I start out doing something like this:
Code:

find . -name '*.mp3' | xargs -i id3v2 -l {}
which, if you are lucky, gives you a nice error message (xargs on other UNIX's ... well ... maybe not so lucky):
Code:

xargs: unmatched single quote; by default quotes are special to xargs unless you use the -0 option
Huh? What's that -0 about? It's meant to be used with a command that emits records separated with null codes and not newline codes. The find command by default uses newlines as record separators, but you can change that with the -print0 option (but then it becomes useful only to commands such as xargs that can slurp in output that contains null bytes as the record separator). Using find in that way, and changing xargs to use the -0 option, yields:
Code:

find . -name '*.mp3' -print0 | xargs -0 -i echo id3v2 -l \"{}\"
Oh, and I wrapped double-quotes around the {} and backslashed them. The backslashes are to escape the double-quotes from the shell that I'm typing the command into, so that the eventual shell will not see the single-quotes and get fouled up. And I added the echo so that I could see the commands before committing to them (like I had mentioned earlier). The resulting output on some of my music that had the single quotes and spaces in them looks like this:
Code:

...
id3v2 -l "./The Cars Greatest Hits/10 Let's Go.mp3"
id3v2 -l "./The Cars Greatest Hits/08 My Best Friend's Girl.mp3"
id3v2 -l "./The Cars Greatest Hits/01 Just What I Needed.mp3"
id3v2 -l "./The Cars-All Mixed Up.mp3"
...

then I can tack on the sh along with other filtering like this:
Code:

find . -name '*.mp3' -print0 | xargs -0 -i echo id3v2 -l \"{}\" | sh -x | grep '^TIT2'
resulting in some meaningful output (notice the "+" are from the -x I fed to sh:
Code:

+ id3v2 -l './The Cars Greatest Hits/10 Let'\''s Go.mp3'
TIT2 (Title/songname/content description): Let's Go
+ id3v2 -l './The Cars Greatest Hits/08 My Best Friend'\''s Girl.mp3'
+ id3v2 -l './The Cars Greatest Hits/01 Just What I Needed.mp3'
TIT2 (Title/songname/content description): My Best Friend's Girl
+ id3v2 -l './The Cars-All Mixed Up.mp3'
TIT2 (Title/songname/content description): Just What I Needed
TIT2 (Title/songname/content description): All Mixed Up

The "+" output lines made it past the final grep most likely because the sh command puts those onto standard error and not onto standard output. Notice also that the standard error output is not synchronized with standard output, which puzzles some users.

Whew! Ok I'm done now (I think). :)

bg

jakykong 04-30-2008 05:35 PM

That certainly answers quite a few questions about the challenges of shell scripting mass file operations (some questions which I hadn't even considered. Strange filenames is a concern with an archiving script, which would need to reproduce the names faithfully).

Thanks!

thomaskirk3 07-16-2013 11:50 AM

This works for me:

mv *.* sub_dir/

jpollard 07-16-2013 07:44 PM

Just "mv * sub_dir" should do the trick. Now if you have 10s of thousands of files in the working directory it might not. But then you can always do the "mv a* subdir;mv b* subdir..." unless you have 10s of thousands of "a*" files...

jdkaye 07-16-2013 11:46 PM

This is a 5 year-old thread. Why bring it back now? The OP is probably long gone.
jdk


All times are GMT -5. The time now is 06:26 AM.