LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (https://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   Script to create folders and subfolders (https://www.linuxquestions.org/questions/linux-newbie-8/script-to-create-folders-and-subfolders-656168/)

leupi 07-16-2008 12:22 PM

Script to create folders and subfolders
 
I need to create a lot of folders and subfolders and was wondering how I might write a script to do this. I need to have a top level folder, 'images' and under that, subfolders numbered sequentially, '100', 101', 102', etc. Within those subfolders I need three additional folders, '192x128', '384x256', and '768x512'. The second level folders (the sequential ones) will number anywhere from ten to 100 folders. Any thoughts on how I can do this?

I am using ImageMagick to resize images in one set of folder and I need to move them over to this new set and unfortunately the folder structure is not the same as where I am getting the images.

Thanks,
Todd

ghostdog74 07-16-2008 12:34 PM

please do man mkdir

cmnorton 07-16-2008 12:53 PM

There's more
 
As an aside, you are more likely to get help by starting this process, and then asking for help.

First, create the script file name using a text editor. Depending what shell you want it to run -- bash -- make sure the first line is #!/bin/bash. On Red Hat systems #!/bin/sh links to /bin/bash, but that is not guaranteed on other distros.

Don't forget to protect the file chmod 775 <script_file_name>, and invoke it (run it) using ./ in front of the script name.

Then, look through man bash and/or try this link to find out about for loops

http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO-7.html

You could probably put all your resolution directories in one of those for loops and then use mkdir within the loop.

3) It also helps for you and those answering you to know your distribution.

leupi 07-16-2008 12:53 PM

man mkdir is one of the first places that I looked. I feel that my needs are a bit more involved than what I can get out of simply the mkdir command. I would imagine that I will need to do some scripting that is a bit more involved than what I am familiar with.

Thanks,
Todd

colucix 07-16-2008 01:12 PM

Quote:

Originally Posted by leupi (Post 3216652)
I feel that my needs are a bit more involved than what I can get out of simply the mkdir command.

Not really...
Code:

mkdir -p images/{100..110}/192x128
mkdir -p images/{100..110}/384x256
mkdir -p images/{100..110}/768x512

in bash the {N..M} syntax produces a sequence of integers from N to M. You should start to read a good bash programming guide for future reference. You can accomplish a lot of tasks in a bunch of seconds using parameter substitution, loops, and so on.

leupi 07-16-2008 01:15 PM

Thanks for the info. I will work on this later when I get home. Seems like I need to set up a 'while' statement to create the first level directories and set up a counter and keep creating directories till the counter increments to a set number. Then I'll need to figure out a way to populate each one of those new directories with three more subdirectories, '192x128', '384x256', and '768x512'. Does that sound like I am on the right track?

Thanks,
Todd

leupi 07-16-2008 01:18 PM

calucix,

Thanks, that sounds like what I need! I just bought 'Learning the Bash Shell' by O'Reilly so I'm sure that that will be a big help. I appreciate the insight. I will be doing a lot of this and this script will be a big time saver for me.

Thanks,
Todd

matthewg42 07-16-2008 01:25 PM

As colucix pointed out, the {n..m} expansion works. You can also use {a,b,c} which will expand to "a" and b" and "c". Combining them, you can quickly make a long list of strings. For example:
Code:

% echo {1..3}{a,b}
1a 1b 2a 2b 3a 3b

instead of passing this list of strings to echo, you can pass their straight to mkdir:
Code:

mkdir -p images/{100..110}/{192x128,384x256,768x512}
The -p option makes it possible makes multi-level sub-directories without a problem. Without it, you have to create "images" before you can create "images/100" and so on.

leupi 07-16-2008 01:34 PM

Matt,

That worked beautifully, that did exactly what I needed, and it was so simple. Now I just need to play with ImageMagick and get the resized files in the appropriate places and I am set. I think that I am going to have to get more familiar with bash, this can be quite the time saver. Thanks so much for everything!

Todd

matthewg42 07-16-2008 01:50 PM

Yeah, shell scripting can be a really boost to productivity. It's not always pretty, but for things like this, you can often spend 2 minutes doing what would take 2 hours with GUI tools.

leupi 07-18-2008 09:06 AM

I completed my project (thanks to you guys) and all went rather well. It went so well in fact that I was handed another one (gotta love working for a nonprofit...). This one is very similar with a bit of a twist. I will have a directory with subdirectories which include images. The subdirectories could be one or more levels deep. I need to convert all of the images to thumbnails and maintain the existing directory structure.

I was looking for a script that would recursively drill down into the directories and convert and images to thumbnails. I found this script and am trying to decipher it:
Code:

new=order-thumb
mkdir /d1/$new
for i in $(find /photo1 -name "*jpg"); do
    img=$(basename $i);dir=$(dirname $i)
    if [ ! -d $new/$dir ]; then mkdir -p $new/$dir; fi
    convert -size 500x500 -geometry 500x500 $i $new/$dir/$img
done

I have my 'Learning the bash Shell' book that I am flipping through trying to translate, but if anyone could offer their expertise that would be greatly appreciated.

Thanks again for everyone's previous help,

Todd

0.o 07-18-2008 09:23 AM

Code:


#This sets a variable
new=order-thumb
#This creates the directord /dl/order-thumb
mkdir /d1/$new

#This uses the output of the find command
#and assigns it to the variable 'i'
for i in $(find /photo1 -name "*jpg");
    do

#For each element found above, assign the image filename
#to the 'img' variable and the path to 'dir'.
        img=$(basename $i);
        dir=$(dirname $i);

#Here we are checking for the directory order-thumb
        if [ ! -d $new/$dir ];
            then
                #If the above directory doesn't exist, create it.
                mkdir -p $new/$dir;
        fi
            #Convert the images and place them into their new directory.
            convert -size 500x500 -geometry 500x500 $i $new/$dir/$img
    done


matthewg42 07-18-2008 10:39 AM

If you put
Code:

set -vx
on the line after the #!/bin/bash line in your script, each statement will be printed after it is read from the file, and also after doing expansion of the command (like putting in the values of variables and so on).

With long scripts, this will often create so much output that you get swamped, but for small fragments it can be very helpful to understand what is going on. for example:
Code:

#!/bin/bash
set -vx
cd $HOME/tmp/test
ls -l *.txt
for f in *.txt; do
  echo "oh hai $f"
done

That will produce this output:
Code:

cd $HOME/tmp/test
+ cd /home/matthew/tmp/test
ls -l *.txt
+ ls -l one.txt three.txt two.txt
-rw-r--r-- 1 matthew matthew 0 2008-07-18 16:18 one.txt
-rw-r--r-- 1 matthew matthew 0 2008-07-18 16:19 three.txt
-rw-r--r-- 1 matthew matthew 0 2008-07-18 16:18 two.txt
for f in *.txt; do
  echo "oh hai $f"
done
+ for f in '*.txt'
+ echo 'oh hai one.txt'
oh hai one.txt
+ for f in '*.txt'
+ echo 'oh hai three.txt'
oh hai three.txt
+ for f in '*.txt'
+ echo 'oh hai two.txt'
oh hai two.txt

...which I hope is useful.

I would like to point out that you might run into problems when there are files with spaces in the file name. Whenever you are iterating over a list of strings, it is prudent to use "double quotes" when taking the value of the iterator variable ($i in this case).

Consider this example:
Code:

touch "file1.txt" "file 2.txt"
for f in *.txt; do
    ls -l $f
done

Here you will have a problem with "file 2.txt" because the ls line will look like this to the shell:
Code:

ls -l file 2.txt
...which it interprets as a request to list two files: "file" and "2.txt".
To correct it, you should add double quotes when using the iterator operator:
Code:

for f in *.txt; do
    ls -l "$f"
done

This is a very a common mistake and can often be difficult to debug if files with spaces in the name are only created some time after the script is written and tested. For this reason, I think it's a good idea to get into the habit of using double quotes when taking the value of variables, even when it is not strictly necessary... just to set that pattern of using the quotes so that you won't fail to do so when it is necessary.

In the case where you are calling find like this, it is worse:
Code:

for i in $(find /photo1 -name "*jpg"); do
    ...
done

Here, the bit inside the $(...) is executed as a shell command, and then the result is split up with IFS being used as a delimiter. In this case, there is no way for the shell to know if there is a space within a file name.

A better construct is like this:
Code:

find /photo1 -name "*.jpg" | while read i; do
    ...
done

There the output of the find command is read line-by-line and each line is read into the i variable. This method will cope with spaces in file names. You still need to remember quote the $i when you use it.

This still does not cope with the case where there is a new line character in a file name, but it's probably safe to assume that you won't encounter that very often.


All times are GMT -5. The time now is 09:02 AM.