3

I have a directory that contains quite a lot of files with names made up of 8 random letters, numbers, _ and -, e.g.:

0dckGYH5.jpg
32Pz5-WQ.png
32_17pxH.png
Hsf4BQW9.jpg
xh-fa3Nu.gif
zYtBEaKA.png
...

Now the task is to go through each of the files, create a directory named after the first 2 characters of the file's name, and move the file into that directory.

The final structure should look like this:

0d
└── 0dckGYH5.jpg
32
├── 32Pz5-WQ.png
└── 32_17pxH.png
Hs
└── Hsf4BQW9.jpg
xh
└── xh-fa3Nu.gif
zY
└── zYtBEaKA.png

Since I don't have permission to install anything on the system, how would I go about doing this with only basic shell commands?

1 Answer 1

7

A straightforward combination of mkdir -p and mv should be enough

for f in *; do d="${f:0:2}"; mkdir -p "$d"; mv -t "$d" -- "$f"; done

Demonstrating:

$ ls
0dckGYH5.jpg  32_17pxH.png  32Pz5-WQ.png  Hsf4BQW9.jpg  xh-fa3Nu.gif  zYtBEaKA.png

$ for f in *; do d="${f:0:2}"; mkdir -p "$d"; mv -t "$d" -- "$f"; done

$ tree .
.
├── 0d
│   └── 0dckGYH5.jpg
├── 32
│   ├── 32_17pxH.png
│   └── 32Pz5-WQ.png
├── Hs
│   └── Hsf4BQW9.jpg
├── xh
│   └── xh-fa3Nu.gif
└── zY
    └── zYtBEaKA.png

5 directories, 6 files

If your system's version of mkdir doesn't have the -p option, then you can test for the directory's existence explicitly e.g.

 for f in *; do d="${f:0:2}"; [[ -d "$d" ]] || mkdir "$d"; mv -t "$d" -- "$f"; done
3
  • Is there a reason you used -t dst -- src rather than src dst? The first form seems to be Linux-specific. Commented Jul 12, 2016 at 20:41
  • @EdwardFalk nope just habit I guess Commented Jul 12, 2016 at 20:44
  • This is very dangerous and it's good that I debugged it first with for f in *; do d="${f:0:2}"; echo "$d"; done. Namely, it tries to move directories to directories too. My fix is: for f in *; do if [ ! -d "$f" ]; then d="${f:0:2}"; mkdir -p "$d"; mv -t "$d" -- "$f"; fi; done Commented Jun 27, 2020 at 23:02

You must log in to answer this question.

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