What command sort’s text files into sub-directories based on date modified
I would like to follow the following command format.
find /path/to/source/* -type f -iname '*.txt' -print0 | xargs -0 mv -t /path/to/target
What command sort’s text files into sub-directories based on date modified
I would like to follow the following command format.
find /path/to/source/* -type f -iname '*.txt' -print0 | xargs -0 mv -t /path/to/target
To help properly, we need a bit more detail:
Also, note that mv does not care about sort order — so the task is really about grouping files by modification date, not sorting.
I need help with this because I’ve never been able to figure the proper placements of the different symbols, options, arguments, varables, etc.
Also I would like to have it to where one script works on both my fiance and mine desktop.
Previously I commented in and out the individual paths.
That can get tedious.
structured as mime-type / year-month please.
Yes, please create automatically as I usually run from terminal without using a current working directory.
I used --backup=numbered previously and now it seemed the copied files are growing so much that my command needs to run without the --backup=numbered allowing the files to be narrowed to a minimum filing structure without deleting the image files jpg png bmp gif etc. I have duplicate image files with different dimensions that I need to keep.
Thanks for the clarification ![]()
Given your requirements:
mime-type / year-month--backup=numberedBelow is a safe and robust Bash solution that works correctly with spaces and special characters.
image/jpeg/2025-01/
text/plain/2024-11/
SOURCE="/path/to/source"
TARGET="/path/to/target"
find "$SOURCE" -type f -print0 |
while IFS= read -r -d '' file; do
mime=$(file --mime-type -b "$file")
date=$(date -r "$file" +%Y-%m)
dest="$TARGET/$mime/$date"
mkdir -p "$dest"
mv -n "$file" "$dest/"
done
mkdir -p ensures directories are created automaticallymv -n prevents overwriting existing filesmv doesn’t care about anyway)a couple more details…
I need help with this because I’ve never been able to figure the proper placements of the different symbols, options, arguments, varables, etc.
Also I would like to have it to where one script works on both my fiance and mine desktop.
Previously I commented in and out the individual paths.
That can get tedious.
That makes sense
— and you’re not alone; shell syntax and quoting rules are one of the hardest parts to get comfortable with.
Here’s how to address both of your concerns:
(1) understanding where things go, and (2) using one script on multiple machines without editing it every time.
Instead of hard-coding paths, we let the script detect the current user and build paths automatically.
That way the same script works on your desktop and your fiancée’s desktop with no commenting/uncommenting.
#!/usr/bin/env bash
SOURCE="$HOME/path/to/source"
TARGET="$HOME/path/to/target"
find "$SOURCE" -type f -print0 |
while IFS= read -r -d '' file; do
mime=$(file --mime-type -b "$file")
date=$(date -r "$file" +%Y-%m)
dest="$TARGET/$mime/$date"
mkdir -p "$dest"
mv -n "$file" "$dest/"
done
$HOME automatically expands to:
/home/wyatt on your system/home/fiancee on hersNo need to edit the script at all
Safe to run from any directory
SOURCE="$HOME/Documents"
mime=$(file --mime-type -b "$file")
$( ... ) means “run this command and store its output”-print0 and -d '' are pairedfind ... -print0 | while IFS= read -r -d '' file
This pair allows filenames with:
Always used together
xargs herexargs becomes fragile once logic is neededIf both of you keep files in the same relative location, you’re done.
If not, you can allow command-line arguments:
SOURCE="${1:-$HOME/source}"
TARGET="${2:-$HOME/sorted}"
Then run:
./sort-files.sh ~/Downloads ~/Sorted
She needs her comp as a coping helps mechanism while I am the overall general maintainer of both systems and other living need’s, including involved internet as a utility as opposed to a luxury.
Thanks to all for the detail’d guidance and help here.
I’ll get this together and see what it throws at us.
Hopefully it all goes well.
That’s completely understandable ![]()
Using a single, portable script with no hard-coded paths is exactly the right approach when you’re maintaining multiple systems and need to keep one of them stable and stress-free.
Take your time testing it on a small set of files first, and adjust as needed.
Also, once you confirm which reply solved your issue, it would be helpful to mark that post as the solution — it really helps future users who run into the same problem.
Looking at the details as an executable file…
Where do I put it and what permissions do I set?
I usually set the permissions as “chmod a+x /location/of/user/level/executable/file.sh”
(Usually in a custom folder in home)
I know there’s a better location to keep the exec files such as this to allow them to be maintained automatically.
For a user-level executable, the usual and recommended place is:
~/.local/bin/
Most modern distributions already have this directory in $PATH.
If it doesn’t exist yet, create it:
mkdir -p ~/.local/bin
Then move the script there, for example:
mv sort-files.sh ~/.local/bin/
You only need to make it executable by the user:
chmod u+x ~/.local/bin/sort-files.sh
Using a+x works too, but u+x is cleaner and safer for user scripts.
Once it’s in ~/.local/bin and executable, you can run it from anywhere:
sort-files.sh
so I don’t need to specify the absolute path to the file in order for it to work when that file is located in ~/.local/bin?
Doing that, will it be auto-maintained when some of the details within the script needs to be updated?
No.
If the script is in ~/.local/bin and that directory is in your $PATH, you can run it by name only:
sort-files.sh
You can confirm with:
echo "$PATH" | tr ':' '\n' | grep .local/bin
If it shows up, no absolute path is needed.
Yes — the file itself is the single source of truth.
When you edit:
~/.local/bin/sort-files.sh
The next time you run:
sort-files.sh
you’re automatically using the updated version.
There’s no caching, no reinstall, no relogin required.
Use a stable name and just edit the file in place:
nano ~/.local/bin/sort-files.sh
As long as:
…every invocation will use the latest changes.
Thanks so much.
I’ve been awake for almost 56 hours straight thanks to my landlord’s employer invoking military standards on civilian living. (yes, I am a US military veteran)
I need sleep and will continue after the well-needed rest.
You’re very welcome. Please get some rest — after being awake that long, that’s the right priority.
Nothing here is urgent, and you can continue once you’re well-rested.
How does this look so far…
Is it ok to create a symlink on the Desktop?
Does it look like it might throw some warnings, errors, etc?
(I plan to run it in a “testing set up” before setting it to the main system)
Where I have the “Set Variables”, is that location in the script ok or does that need to be where you originally put them?
#!/usr/bin/env bash
### Specify file name for pattern matching
## Guidance from - @TheFu @ian-weisser
# sort-files.sh
## Note: Spaces at the beginning of commands to reduce recording in .bashrc
## and/or .bash_history
## Guidance from - @guiverc
###================================================================###
### Script Location
## For a **user-level executable**
## the usual and recommended place is
# $ ~/.local/bin/
## Most modern distributions already have this directory in `$PATH`.
## If it doesn’t exist yet, create it:
# $ mkdir -p ~/.local/bin
## Then move the script there, for example:
# $ mv sort-files.sh ~/.local/bin/
###================================================================###
### Set Permissions
## User level scripts need to be executable by the user
## Using `a+x` works too, but `u+x` is cleaner and safer for user scripts
# $ chmod u+x ~/.local/bin/sort-files.sh
### Run Script From Anywhere
# $ sort-files.sh
###================================================================###
### Set Variables
# Source Variables
SOURCE="$HOME/path/to/source"
# Target Variables
TARGET="$HOME/path/to/target"
###================================================================###
### The Script - Portable (no hard-coded usernames)
find "$SOURCE" -type f -print0 |
while IFS= read -r -d '' file; do
mime=$(file --mime-type -b "$file")
date=$(date -r "$file" +%Y-%m)
dest="$TARGET/$mime/$date"
mkdir -p "$dest"
mv -n "$file" "$dest/"
done
###================================================================###
######################################################################
Yes, absolutely.
That’s actually a good usability choice.
Example:
ln -s ~/.local/bin/sort-files.sh ~/Desktop/sort-files
Nothing obvious ![]()
As written, it should run cleanly assuming:
SOURCE existsTARGET exists (or is creatable)file command is installed (it usually is)Optional (not required):
You could add a quick sanity check later, but for testing this is fine.
Yes — this is exactly where they should be.
Best practice is:
You did that correctly. There is no requirement that they be in a specific absolute position, only that they’re defined before use.
find are harmless (shell ignores them)You’re doing this the right way. Test it on a small dataset, then promote it to the main system when ready.
I think it is very important to clarify whether both machines are the same in terms of the flavour and version installed (as well as the filesystem type).
Running a test on a small batch would definitely be advisable.
Final point: does the script remove the empty source folders and is this something you want to happen?
Her’s and mine both are running Lubuntu 24.04.
Absolutely
I usually set up a temporary directory on the desktop with sub-directories.
However, using this bash setup is helping me require better ways of doing things.
Thats a good point.
There’s a command in my original executable that deletes the empty directory(s) in the source directory
It may be more safe to use “rmdir” instead of “find”.
(That might depend on your individual use case as to which command you might need)
One of the 2 commands removes only empty directories.
$ find "$SOURCE"/* -type d -empty -delete
Terminal threw a couple complaints…
wyatt@wyatt-82xb:~$ mkdir -p ~/.local/bin
wyatt@wyatt-82xb:~$ mv sort-files.sh ~/.local/bin/
mv: cannot stat 'sort-files.sh': No such file or directory
For this instance, I used my old command
wyatt@wyatt-82xb:~$ mv /home/wyatt/Desktop/sort-files.sh ~/.local/bin/
wyatt@wyatt-82xb:~$ chmod u+x ~/.local/bin/sort-files.sh
The chmod u+x performed as expected.
And finally…the following…
wyatt@wyatt-82xb:~$ sort-files.sh
find: ‘/home/wyatt/path/to/source’: No such file or directory
wyatt@wyatt-82xb:~$
Those messages are expected and don’t indicate a problem with the script ![]()
The mv: cannot stat error happened because the file wasn’t in the current directory. Using the full path from Desktop was the correct fix.
The find: No such file or directory message is because
SOURCE="$HOME/path/to/source"
is just a placeholder and needs to be replaced with a real, existing path.
Once SOURCE and TARGET are set to valid directories, the script should run without errors.