LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (https://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   Move all files not in a directory into a subdirectory named for each given file (https://www.linuxquestions.org/questions/linux-newbie-8/move-all-files-not-in-a-directory-into-a-subdirectory-named-for-each-given-file-920099/)

Nix 12-22-2011 04:40 PM

Move all files not in a directory into a subdirectory named for each given file
 
Hi

Looking for some help with a script that will take all files in any given root folder (which are not already in a folder) and put them into separate folders with the name of each given file.

Any ideas?

Thank you!

Dan

chrism01 12-22-2011 05:46 PM

Can you show us what you've got so far; are you using bash?
You'll want these links
http://rute.2038bug.com/index.html.gz
http://tldp.org/LDP/Bash-Beginners-G...tml/index.html
http://www.tldp.org/LDP/abs/html/

You'll prob want the file tests http://tldp.org/LDP/abs/html/fto.html, conditionals http://tldp.org/LDP/Bash-Beginners-G...l/chap_07.html, loops http://tldp.org/LDP/Bash-Beginners-G...l/chap_09.html

Nix 12-22-2011 05:49 PM

Hey Chris!

Thank you for helping :)

I am reading around on tldp.org trying to figure out a way to go about this

a few things:

I am not a programmer or a scripter, i just found something i want to do with some organization of files and no conventional tool to do it so I am making a scripting attempt :)

so thus far, i have a blank script page with just some pseudo instructions for one way to go about it.

I really am not sure where to start...

Still looking up the commands that will really work with this kind of thing

chrism01 12-22-2011 05:56 PM

Well, bookmark the main links I gave you and read the Rute Tutorial one (v good) & reference the other 2.
In particular, as mentioned, the specific techniques mentioned in the last 3 links.
A good tip when starting out; don't try to write the entire script in one go, break it down into stages and test each one.
For example, in your case I'd start with trying to find all entries in the root dir and determine what type they are (hint: see file tests link ;) )

Easy to search for cmds here http://linux.die.net/man/

You'll prob want find cmd http://linux.die.net/man/1/find or maybe ls http://linux.die.net/man/1/ls

Nix 12-22-2011 05:59 PM

yea that's what im doing, just going piece by piece... identify if it's a file or a directory... then basically capture the directory into an array and then process down the array creating a folder for every found file's name... once that's done... check to see if a file's corresponding directory name exists and if it does then move the file into the directory?


Is that a good approach?

Sounds simple enough tho im not sure how to deal with the array... and still working on just getting an output of all the regular non directory files in a folder.

Thanks for your links, looking through them

chrism01 12-22-2011 06:10 PM

Don't need the array, just process each entry as you retrieve it; see loops link :)
Re dir create; check return code of dir create as you do it; no need to scan twice; google ' bash $? ' ;) http://tldp.org/LDP/abs/html/internalvariables.html http://tille.garrels.be/training/bas...ml#table_03_03

PS: FYI *nix is case sensitive!
Also, don't put spaces in filenames; its syntactically valid (unfortunately), but by default its usually interpreted as a parameter separator; you can imagine the trouble that causes ... ;)

Nix 12-22-2011 06:38 PM

o_O

Nix 12-22-2011 07:25 PM

This is what i've pieced together so far

Code:

for FILE in *.{avi}
do
  DIR="{$FILE%.*}
  mkdir -p $DIR
  mv $FILE $DIR
done

doesn't work of course

David the H. 12-23-2011 08:22 AM

Please use [code][/code] tags around your code and data, to preserve formatting and to improve readability.

And just saying it "doesn't work" is not very helpful. In what way doesn't it work? What results and error messages do you get?

You have the basic idea right, but your implementation of it is broken. You have three syntax errors in your short loop. Look carefully at these two parts:

Code:

*.{avi}
"{$FILE%.*}


As a new scripter, I think you'll get a better understanding if you start with the Bash Guide, rather than the tldp stuff. It presents all the basic concepts in an easy-to-read manner:

http://mywiki.wooledge.org/BashGuide

And when you're finished, continue on to these pages from the same site:

http://mywiki.wooledge.org/Arguments
http://mywiki.wooledge.org/WordSplitting
http://mywiki.wooledge.org/Quotes

http://mywiki.wooledge.org/glob
http://mywiki.wooledge.org/BashFAQ/073
http://mywiki.wooledge.org/BashFAQ/100

http://mywiki.wooledge.org/BashPitfalls
http://mywiki.wooledge.org/BashFAQ

PS: There's nothing wrong with storing the names in an array first either. It's just another way to go about it. In this case though, it adds an unnecessary step.

Nix 12-23-2011 05:29 PM

David, thank you for your well rounded follow up comment.

I will be sure to make use of all the resources you have outlined as well as uphold community principals for posting.

Here is what I have learned in one day from reading around on the net. My first successful shell script!
No Hello World or anything. Straight to this :)

We have gone from:

Code:

for FILE in *.{avi}
do
  DIR="{$FILE%.*}
  mkdir -p $DIR
  mv $FILE $DIR
done

To my final working version of this!

Code:

#!/bin/bash

clear

echo "################################################################"
echo "Hello," $USER
echo "Bash version is" $BASH_VERSION
echo "Current directory is" $PWD
echo "Changing directory..."
cd /home/admin/Test
echo "Working directory changed to:" $PWD
echo "################################################################"

# save and change IFS
OLDIFS=$IFS
IFS=$'\n'
 
for FILE in *
do
  DIR="$FILE"
echo "Processing" $FILE
  mkdir ${DIR%.*}
echo "Creating Directory For" ${FILE%.*}
  mv $FILE ${DIR%.*}
echo "Moving $FILE into Directory"
echo "Processing next file..."
done

I realize this is far from perfect, however it is working for me. and I will further play with it to refine input variables for directory selection, and maybe some error handling, or for setting the files to include/exclude // extensions.. never know. I am sure I will use this again!

Thank you all for your suggestions and assistance! :)

David the H. 12-24-2011 01:40 PM

That's certainly better. Good work!

There are a couple of things you should try to ingrain into your coding behavior from the outset, however.

1) Learn to always quote your variable expansions, especially when working with filenames. I know you set IFS to newline this time, so this script is safe from word-splitting, but you should still get into the habit of doing it by default. It's just that important.

Longer strings like this can and should be quoted as a single unit:

Code:

echo "Processing" $FILE
#better:
echo "Processing $FILE"

Environment variables are generally all upper-case, so it's a good idea to give your own script variables lowercase or mixed case names to differentiate them. Not really an important point, but it is a traditional practice.

Oh, and you really don't need to back-up the old IFS setting in a script unless you have a need to revert back to it later on.

2) If you haven't seen it yet, the last page of the Guide has a section on formatting and readability. Properly indenting and blocking your code makes for code that's more readable and easily debuggable.

Good commenting is important too. What your script is doing may seem obvious to you now, but I guarantee that in a few years you'll look back on some of your old code and wonder what the heck that's supposed to be doing (and possibly what you were high on when you wrote it ;)). Learn to comment as you code.

And while not absolutely necessary, a lot of us think the "do/then" keywords read better when placed on the same line as the "for/while/until/if" keywords they're paired with.

So here's how I would do your main loop from above:
Code:

for file in *; do        # I thought you wanted to use *.avi here?
        echo "Processing $file"

        echo "Creating Directory $dir"
        dir="${file%.*}"
        mkdir -p "$dir"

        echo "Moving $file into $dir"
        mv -t "$dir" "$file"

        echo "Processing next file..."
done


("mkdir -p" has the side-effect of it not erroring if the dirname already exists, and explicitly defining the target directory with "mv -t" is safer than depending on it simply using the last argument. Also, in this case the echo commands act pretty well as comments, so we don't really need to explain it any further. You could however just use the -v option in the above commands instead, and skip the echos. )


All times are GMT -5. The time now is 10:07 AM.