4

I have a directory with huge number of files with different extensions. What I want to do is to move each extension to a folder with name the extension itself, and those files without extension move to a folder named unkown.

For example I have the files a.txt, b.txt ,a.pdf, b.pdf , a.mp4 , file, newfile ....

The result would be 4 dirs named txt, pdf, mp4 , unkonw

the txt dir contains the files a.txt, b.txt

the pdf dir contains the files a.pdf, b.pdf

the mp4 dir contains the files a.mp4

the unkonw dir contains the files file, newfile

3
  • I think you made a mistake in your question. you mean to move a.txt and b.txt to the txt directory and file and newfile to the unknown directory. Also I want to ask are there only these four extensions or are there many more?
    – Rumesh
    May 30, 2015 at 10:12
  • yeah sorry typo error
    – Maythux
    May 30, 2015 at 10:12
  • No there is much more this is just an example
    – Maythux
    May 30, 2015 at 10:13

2 Answers 2

6

Here's another way:

mkdir -p unknown; 
for f in *; do 
[[ $f =~ \. ]] && mkdir -p "${f##*.}" && 
               mv "$f" "${f##*.}"/ || 
mv "$f" unknown/; done

Explanation

  • && means "run the command on the right only if the command on the left was successful".
  • || means "run the command on the right only if the command on the left failed". The two symbols combined can work like an if/else block.
  • mkdir -p unknown; : create the unknown directory. The -p is there so that mkdir won't complain if the directory exists.
  • for f in * : for all files and directories in the current directory.
  • [[ $f =~ \. ]] && : if the current file/dir name contains a ., if it has an extension, then...
  • mkdir -p "${f##*.}"/ : the construct ${var##pat} will remove the longest match of pat from the beginning of variable $var. Here, the pat is anything up to a dot, so this will leave only the extension. This command, therefore, creates the extension's directory if it doesn't exist.
  • mv "$f" "${f##*.}"/ : The mv then moves the file into the relevant directory. || mv "$f" unknown/; : if the previous command failed (if this file/directory) does not have an extension, move it to unknown.

Note that this will print this error message, but you can safely ignore it:

mv: cannot move ‘unknown’ to a subdirectory of itself, ‘unknown/unknown’

If you need to move only files and no directories (the commands above will also move a directory called dir.foo into foo/), use this instead:

mkdir -p unknown; 
for f in *; do 
[[ -f $f ]] && 
    if [[ $f =~ \. ]]; then 
        mkdir -p "${f##*.}" && 
        mv "$f" "${f##*.}"/; 
    else mv "$f" unknown/; fi; 
done
4

This bash script will do that: run it with bash script.sh <path> or ./script.sh <path>, where <path> is the path to the folder containing the files:

#!/bin/bash

for path in ${1}/*
do
    if [ -f "${path}" ]
    then
        extension="$(<<< "${file}" sed -rn 's/^.*\.(.*)$/\1/p')"
        if [ -n "${extension}" ]
        then
            mkdir -p "${1}/${extension}"
            mv "${path}" "${1}/${extension}"
        else
            mkdir -p "${1}/unknown"
            mv "${path}" "${1}/unknown"
        fi
    fi
done

tree output before and after running the script on a tmp directory:

ubuntu@ubuntu:~$ tree tmp
tmp
├── a.mp4
├── a.pdf
├── a.txt
├── b.pdf
├── b.txt
├── file
├── folder
└── newfile

1 directory, 7 files
ubuntu@ubuntu:~$ bash script tmp/
ubuntu@ubuntu:~$ tree tmp
tmp
├── folder
├── mp4
│   └── a.mp4
├── pdf
│   ├── a.pdf
│   └── b.pdf
├── txt
│   ├── a.txt
│   └── b.txt
└── unknown
    ├── file
    └── newfile

5 directories, 7 files
5
  • Is it a simpler method to get the extension?
    – Maythux
    May 30, 2015 at 10:12
  • @Maythux I'm no bash parameter expansion expert, but according to this answer, filename="$(basename "$file")"; extension="${filename##*.}" will do
    – kos
    May 30, 2015 at 10:16
  • easily you can replace your extension line with this extension="${file##*.}"
    – Maythux
    May 30, 2015 at 10:19
  • Also still some weakness in your script, it will move folders also not only files, so you have to check if it is a file, please fix it to mark it again as answer
    – Maythux
    May 30, 2015 at 10:20
  • @Maythux I updated to exclude folders, however I'm having some troubles using the parameter expansion suggested in that answer. I'm unable to test further as of now, I'll update later and drop you a comment once done
    – kos
    May 30, 2015 at 10:57

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