1

I have a folder containing thousands of files and directories. I would like to move all the files that are not contained in a sub directory into a directory and name it the file name, while leaving the files already inside of directories alone, ie:

  • create 'newdir'
  • move 123.mp4 into 'newdir'
  • change name 'newdir' to '123'
  • repeat
1
1

Command

This command was tested in a bash shell.

for x in *;do if [[ -f $x ]];then mkdir newdir;mv "$x" newdir/.;mv newdir "${x%.*}";fi;done

Explanation

The code shown below is not necessary commands you can execute. Rather, what is shown is an explanation of various parts of the code shown above.

Loop through all file names in current directory.

for x in *;do ... done

Only do regular files. (Skip the directories.)

if [[ -f $x ]];then ... fi;

Make new directory newdir.

mkdir "newdir";

Move file x to new directory newdir.

mv "$x" newdir/.;

Rename newdir to the name of the desired new directory. (Set newdir to file name x after removing the last . and all characters that follow.)

mv newdir "${x%.*}";

Comments

If the desired directory already exists, then the newdir folder (containing the file) will be moved to the desired directory. For example, if the file 123.mp4 and directory 123 both already exist, then file 123.mp4 will end up in 123/newdir. You can test to see if this occurred by entering the command given below.

find . -name newdir

For example, if 123/newdir/123.mp4 existed, then the follow output would appear.

./123/newdir
0
0

Limitations:

  • Doesn't work if you have any file with no extension. 1

  • Exception handling must be added in case a directory already exists.

  • Worked on Mojave. Python 3.7.3, but the posts listed below often don't mention their versions either.

  • Did not post on Code Review.

  • #%% are for VSCode's Jupyter extension.

#%%
import os

# %%
source = "/Users/me/Desktop/folder" # notice the missing last "/"
filenames = next(os.walk(source))[2]
filenames = [ x for x in filenames if not ".DS_Store" in x]
#%%
dirpaths = [os.path.splitext(file)[0] for file in filenames]

# %%
def making(directory,source=source):
   directory = os.path.join(source,directory+"/")
   os.makedirs(directory)

a = [making(directory) for directory in dirpaths]     #list comprehension could be faster than loops.

# %%

def movingfiles(onefile, source=source):
   os.rename(source + "/" + onefile, source + "/" + os.path.splitext(onefile)[0] + "/"  + onefile ) 

b = [movingfiles(onefile) for onefile in filenames]       #useless list again.

Sources in order of need:

5
  • I'm not all that fluent in Python, but you probably could work around the "Doesn't work if you have any file with no extension" constraint by adding some logic to the function where you call os.rename. – nohillside Dec 16 '19 at 10:13
  • Also, your function names don't really help in making the code understandable. – nohillside Dec 16 '19 at 10:13
  • That part is documented in last link on SO and limitation comes from directory making, which I shortened the length of, by making it with the file name directly instead of using an intermediate name. – anki Dec 16 '19 at 10:14
  • Ah, right, you create all the subdirectories first (with func) and then do the move with funct (did I already mention that your function names don't help :-)). Anyway, I would aim for a solution where you only have to process the list of files once and then handle all the special cases (including creation of directories) within the function called for each file. – nohillside Dec 16 '19 at 10:19
0

If you want to use find to avoid the typical problems with filenames containing spaces and other whitespace characters:

find . -maxdepth 1 -type f ! -name '.DS_Store' -exec bash -c '
    t="${1:2}";
    mkdir FluffyBird;
    mv "$t" FluffyBird/
    mv FluffyBird "${t%.*}"' _ {} \;

Substitute FluffyBird with whatever string which isn't a filename in the folder already.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .