0

I have a directory with files like these

2022-11-08-0001.gzip
2022-11-08-0002.gzip
2022-11-08-0003.txt
2022-11-08-0004.png
2022-11-08-0005.txt
2022-11-08-0006.txt
2022-11-08-0007.png
2022-11-08-0008.txt
2022-11-08-0009.txt
2022-11-08-0010.png

and want to split them into sub directories like so

/gzip
2022-11-08-0001.gzip
2022-11-08-0002.gzip

/png
2022-11-08-0004.png
2022-11-08-0007.png
2022-11-08-0010.png

/txt
2022-11-08-0003.txt
2022-11-08-0005.txt
2022-11-08-0006.txt
2022-11-08-0008.txt
2022-11-08-0009.txt

I found this short and sweet solution, but I could not customize it to my needs because the length of the file extensions vary. The base names of the files are of equal length, though.

2 Answers 2

3

With zsh (and assuming the pattern 2022-*.* matches all relevant files, i.e., files with names starting with the string 2022- and containing at least one dot):

for name in 2022-*.*; do
    mkdir -p $name:e && mv $name $name:e
done

In zsh, $variable:e will be the same as $variable, but with everything before the last dot removed (leaving the "extension").

Testing:

$ tree
.
|-- 2022-11-08-0001.gzip
|-- 2022-11-08-0002.gzip
|-- 2022-11-08-0003.txt
|-- 2022-11-08-0004.png
|-- 2022-11-08-0005.txt
|-- 2022-11-08-0006.txt
|-- 2022-11-08-0007.png
|-- 2022-11-08-0008.txt
|-- 2022-11-08-0009.txt
`-- 2022-11-08-0010.png

0 directories, 10 files
$ for name in 2022-*.*; do mkdir -p $name:e && mv $name $name:e; done
$ tree
.
|-- gzip
|   |-- 2022-11-08-0001.gzip
|   `-- 2022-11-08-0002.gzip
|-- png
|   |-- 2022-11-08-0004.png
|   |-- 2022-11-08-0007.png
|   `-- 2022-11-08-0010.png
`-- txt
    |-- 2022-11-08-0003.txt
    |-- 2022-11-08-0005.txt
    |-- 2022-11-08-0006.txt
    |-- 2022-11-08-0008.txt
    `-- 2022-11-08-0009.txt

3 directories, 10 files

Using zsh from bash (and using a short form of for in the zsh -c script, and condensing the name variable's name down to n):

zsh -c 'for n; mkdir -p $n:e && mv $n $n:e' zsh 2022-*.*
1
  • So nice! Zsh also has the much nicer glob options. Commented Nov 9, 2022 at 2:02
1

You would simply go through every file name, make the matching directory if it doesn't exist yet, and move the file there. Something like

#!/bin/bash
for filename in *; do
  # if filename is not a regular file, skip
  [ -f "${filename}" ] || continue

  # ${}: variable expansion
  # ${variable/pattern/replacement}: Pattern Replacement
  # pattern begins with #, meaning it must start at beginning of name
  # pattern is *., meaning "all up to the last dot"
  # replacement is empty
  suffix="${filename/#*./}"

  # skip files with no extension
  [ "${suffix}" = "${filename}" ] && continue

  # make that directory. Or ignore the fact it's already made.
  mkdir -p "${suffix}"
  mv "${filename}" "${suffix}"
done

You must log in to answer this question.

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