Apple - How to replace a folder that's name is a date i.e. YYYYMMDD with folder hierarchy of year, month, date?
You can use the following in Terminal. cd
to the containing folder, then run the following:
find . -type f -exec bash -c \
'F=$(sed -E "s#^\./([0-9]{4})([0-9]{2})([0-9]{2})#\1/\2/\3#" <<< $1);\
mkdir -p -- $(dirname "$F");\
mv -- "$1" "$F"' - {} \;
find . -type f
obtains every file in the current directory recursively.
-exec bash -c
opens a shell to run the following commands.
F=$(…)
opens a subshell and uses sed on the file path to manipulate the path into the folders.
^\./([0-9]{4})([0-9]{2})([0-9]{2})
is a regex with three capture groups, as follows:
\1/\2/\3
is replacement, where each capture group (\1
, etc) are separated by /
.
mkdir -p -- $(dirname "$F")
creates the directories to move the files into.
mv -- "$1" "$F"
moves each file into its corresponding folder.
This takes the hierarchy on the left and converts it to the hierarchy on the right:
├── 20170201 └── 2017
│ └── abcdefghij ├── 02
└── 20170302 │ └── 01
└── abcdefghij 2 │ └── abcdefghij
└── 03
└── 02
└── abcdefghij 2
If there are other files in the containing folder with a date as a name, they will be moved as if they are a folder. To prevent this, replace the second line with:
'F=$(sed -E "s#^\./([0-9]{4})([0-9]{2})([0-9]{2})(?:/.+)#\1/\2/\3#" <<< $1);\
The (?:/.+)
ensures that the path has a subsequent component, therefore ignoring anything without a child in the parent directory which are files.
Assuming all these YYYYMMDD folders are part of the same parent directory you could run
cd PARENT_DIRECTORY
for d in */; do
[[ $d =~ [0-9]{8}/ ]] || continue
mkdir -p -- "${d:0:4}/${d:4:2}"
mv -- "$d" "${d:0:4}/${d:4:2}/${d:6:2}"
done
- The
for d in */; do
loop reads all directory entries, the trailing/
ensures that only directory names actually match [[ $d =~ [0-9]{8}/ ]]
tests whether the current entry consists of 8 digits, and continues with the next entry if not${d:0:4}/${d:4:2}/${d:6:2}
uses parameter expansion withinbash
to create a string containing the new path- The
--
in bothmkdir
andmv
prevents problem in case the directory or file name starts with a-
. This can't happen here but it's probably good practice anyway.
Thanks to @terdon and @user3439894 for ideas on how to improve the original script.