Build a File Organizer with Linux
Write a Bash script that automatically sorts files into folders by type.
Introduction
30 Second Summary
Everyone has that one folder on their computer where files pile up with no rhyme or reason. Screenshots mixed with PDFs mixed with random code files. Cleaning it up by hand takes forever, and it comes back messy within a week.
In this project, you will install a Linux environment on your Windows machine and write a Bash script that automatically sorts a chaotic folder of files into neatly labeled categories.
What You'll Build
You will type a single command, watch 15+ scattered files fly into organized folders (Images, Documents, Audio, Video, Code, Archives), and see a printed summary of exactly what moved where.
By the end of this project, you'll have:
- A reusable script called organizer.sh that you can run with ./organizer.sh and watch a messy folder sort itself in under a second.
- Confidence navigating any Linux file system, creating directory structures, and moving files using the 20 most common commands.
- The ability to chain commands with pipes to instantly answer questions about your files like how many there are, what types they include, and where they live.
- Secret Mission: Add automatic logging and handle tricky edge cases like files with no extension.
Are there any prerequisites?
You just need a Windows 10 or Windows 11 PC. This project walks you through installing everything else, including WSL (Windows Subsystem for Linux) and Ubuntu. No prior Linux experience required.
Before We Start
Before we dive in, let's lock in what you're about to build and why it matters. Taking a moment to commit to the goal helps you stay oriented as you learn new commands and concepts.
Install WSL and Launch Ubuntu
Every command in this project runs inside a Linux terminal. You need a Linux environment on your Windows machine to follow along.
WSL (Windows Subsystem for Linux) gives you a full Ubuntu terminal directly on Windows. No virtual machines, no dual-booting. It installs with a single command and uses barely any resources when idle.
In this step, get ready to:
- Install WSL with Ubuntu using a single PowerShell command.
- Create your Linux user account.
- Update all packages and confirm your environment is ready.
Install WSL with Ubuntu
WSL requires a single command run from an elevated PowerShell prompt. The command downloads and installs both WSL and the Ubuntu distribution in one go.
- Press the Windows key to open your search bar.
- Type PowerShell.
- Right-click Windows PowerShell and select Run as administrator.
- Click Yes when the User Account Control dialog appears.
Why do I need Administrator mode?
WSL installs a full Linux kernel on your machine. Windows requires elevated privileges for system-level changes like this.
- Install WSL and Ubuntu by running this command:
wsl --install
What does this command do?
This single command enables the WSL feature, downloads the Linux kernel, and installs Ubuntu as your default Linux distribution. It handles everything in one step.
You should see output confirming that Ubuntu is being downloaded and installed. Once it finishes, it will ask you to restart your computer.
- Restart your computer when prompted.
Seeing an error about Windows version?
WSL requires Windows 10 version 2004 (Build 19041) or higher, or Windows 11. If you see an error, check your Windows version by pressing Windows + R, typing winver, and pressing Enter.
If your build number is below 19041, update Windows through Settings > Update & Security > Windows Update before retrying.
Help me fix my WSL installation error.
Launch Ubuntu and create your account
After restarting, Ubuntu needs a one-time setup where it creates your Linux user account. This account is separate from your Windows login.
- Press the Windows key to open your search bar.
- Type Ubuntu and press Enter to open it.
Ubuntu will take a minute to decompress its files on first launch. Then it prompts you to create a username and password.
- Enter a username when prompted. Use all lowercase letters with no spaces (e.g. alex).
- Enter a password when prompted. Type it again to confirm.
Why can't I see my password as I type?
Linux hides password input completely. No dots, no stars, nothing. This is a security feature, not a bug. Just type your password and press Enter. It is recording every keystroke even though the screen looks blank.
After confirming your password, you should see a colored command prompt that looks something like yourname@DESKTOP:~$. This means you are now inside a Linux terminal.
Ubuntu didn't ask for a username?
If Ubuntu opened briefly during the restart and set up automatically, it may have defaulted to the root user. Close the Ubuntu window, open it again from the Start menu, and check if it prompts you now.
Help me set up my Ubuntu user account.
Update packages and verify your environment
Your Ubuntu installation ships with a package list that may be outdated. Updating ensures you have the latest versions of all installed software before you start working.
- Update your package list and upgrade all packages by running this command:
sudo apt update && sudo apt upgrade -y
What does this command do?
This is actually two commands chained with && (which means "run the second only if the first succeeds").
- sudo apt update refreshes the list of available packages from the internet.
- sudo apt upgrade -y installs newer versions of everything already installed. The -y flag automatically accepts all prompts.
You will see a lot of output scrolling by as packages download and install. This can take a minute or two depending on your internet speed. Wait until you see your command prompt appear again.
Now it is time to confirm everything is working. Before you run the next command, what do you expect to see from a command that checks your Linux distribution?
- Verify your environment by running this command:
lsb_release -a
You should see Ubuntu version information printed to the terminal, including lines for Distributor ID, Description, Release, and Codename. This confirms your Linux environment is fully set up and ready.
Seeing 'command not found'?
Make sure you are typing the command inside the Ubuntu terminal (the dark window with your Linux username in the prompt), not in PowerShell. PowerShell does not have Linux commands.
If you accidentally closed Ubuntu, reopen it from the Start menu by searching for Ubuntu.
Help me troubleshoot my Ubuntu terminal.
Why WSL instead of a virtual machine?
A virtual machine (like VirtualBox) would give you the same Ubuntu environment, but it takes 20+ minutes to set up and uses significantly more RAM and disk space. WSL runs natively inside Windows with near-zero overhead when idle.
You also get seamless access to your Windows files from inside Linux (they live under /mnt/c). No shared folders to configure.
Your Linux environment is ready. Next up, you will create a messy folder full of mixed files and learn the core commands for navigating and inspecting them.
Create a Messy Folder and Explore It
Your Ubuntu environment is ready to go. Now you need something to actually organize.
Before you can build an organizer script, you need files to organize. Creating them by hand teaches you the core commands for navigating and creating files: mkdir, touch, cd, ls, and pwd.
In this step, get ready to:
- Create a project folder and navigate into it.
- Create 15 sample files of different types.
- Explore the folder with listing and inspection commands.
Create your project folder
Every project starts with a dedicated folder. You will create one in your home directory and move into it so all your work stays in one place.
- Create your project folder and navigate into it by running this command:
mkdir ~/messy-folder && cd ~/messy-folder
What does this command do?
- mkdir ~/messy-folder creates a new directory called messy-folder inside your home folder (~ is shorthand for your home directory).
- && chains two commands together. The second command only runs if the first one succeeds.
- cd ~/messy-folder changes your current directory into the folder you just created.
- Confirm your location by running:
pwd
You should see /home/yourusername/messy-folder printed to the terminal, where yourusername is the Linux username you created in the previous step.
Seeing 'directory already exists'?
If you already created messy-folder in a previous attempt, the mkdir command will fail and cd will not run. Run cd ~/messy-folder by itself to navigate into the existing folder.
help me fix a 'directory already exists' error with mkdir
Create 15 sample files
You need a realistic mix of file types to test your organizer on. The touch command creates empty files instantly.
- Create 15 sample files of different types by running:
touch report.pdf notes.txt photo.jpg screenshot.png song.mp3 podcast.wav video.mp4 clip.mov style.css app.js index.html backup.zip data.tar logo.svg readme.doc
What does touch do?
touch creates a new empty file for each name you give it. The file extensions (.pdf, .jpg, .mp3, etc.) are just part of the filename in Linux.
Unlike Windows, Linux does not rely on extensions to determine file types. These extensions are labels for humans and for your organizer script to sort by.
- Confirm the files were created by running:
ls
You should see all 15 filenames printed in the terminal.
Seeing fewer than 15 files?
Check for typos in the touch command. If you missed a file, run touch again with just the missing filename (e.g. touch logo.svg). Running touch on a file that already exists does not overwrite it.
help me figure out which files I'm missing after running touch
Explore your files
Listing files is something you will do constantly in Linux. There are several ways to look at what is in a directory, each giving you different information.
- Before you run the next command, predict: how many total lines do you expect in a detailed listing of 15 files?
- Run this command to see detailed file information:
ls -la
What does ls -la show?
The -l flag shows a long listing with permissions, owner, size, and modification date for each file. The -a flag includes hidden files (files starting with a dot).
You will see more than 15 lines because the listing also includes . (current directory) and .. (parent directory) entries, plus a "total" line at the top.
- Run this command to see what Linux thinks each file type is:
file *
Why does file report everything as 'empty'?
The file command inspects a file's actual contents to determine its type. Since touch created empty files, file reports them all as empty.
This proves Linux does not use file extensions to determine type. Your organizer script will use extensions as sorting labels, but Linux itself looks at content.
You now have 15 files sitting in one folder with no organization whatsoever. This is the mess your script will eventually clean up.
Your messy folder is ready. Next up, you will try to organize these files by hand and discover exactly why scripting exists.
Try to Organize Manually
Your messy folder is set up with 15 files of every type. Time to bring some order to this chaos.
The most natural approach is manual organization. You'll create category folders and move files into them one by one using mkdir and mv.
In this step, get ready to:
- Create category folders and manually move files into them.
- Count the remaining files to check your progress.
- Reset the folder to prepare for automation.
Create folders and move files by hand
You have image files and document files mixed together with audio, video, and code. You'll start by sorting just two categories: images and documents.
- Create two category folders by running this command:
mkdir Images Documents
- Move the image files into the Images folder by running these commands:
mv photo.jpg Images/
mv screenshot.png Images/
- Confirm the images moved by running:
ls Images/
You should see photo.jpg and screenshot.png listed.
- Now move two document files into the Documents folder by running these commands:
mv report.pdf Documents/
mv notes.txt Documents/
- Confirm the documents moved by running:
ls Documents/
You should see report.pdf and notes.txt listed.
What do mkdir and mv do?
The mkdir command creates new directories. You can create multiple at once by listing their names separated by spaces.
The mv command moves a file from one location to another. The first argument is the file, and the second is the destination folder (the trailing / tells Linux it's a directory).
Count what's left
You've organized 4 files into 2 folders. Before you check how much work remains, take a guess: how many items do you think are still sitting in the root of your messy folder?
- See what's still in the root by running:
ls
You'll see 11 files still sitting in the root alongside your two new folders. Four files moved after typing four separate commands.
- Count the items precisely by running:
ls -1 | wc -l
You'll see 13 in the output. That's 11 unorganized files plus the 2 folders you created.
Imagine if this folder had 200 files. Moving them one by one is not going to work.
Why is this a problem?
Each mv command handles exactly one file. For 15 files across 6 categories, you'd need to type at least 15 individual move commands. For a real Downloads folder with hundreds of files, manual sorting takes forever and invites mistakes.
This repetitive pain is exactly what scripting solves.
Reset the folder for automation
You've proven the manual approach doesn't scale. Now you'll move everything back to its starting position so you have a clean slate for the automated approach coming next.
- Move all files back to the root and remove the empty folders by running this command:
mv Images/* . && mv Documents/* . && rmdir Images Documents
What does this command do?
This chains three operations together with && (which means "run the next command only if the previous one succeeded").
- mv Images/* . moves all files from Images back to the current directory (. means "here").
- mv Documents/* . does the same for the Documents folder.
- rmdir Images Documents removes the now-empty directories.
- Confirm everything is restored by running:
ls
You should see all 15 original files back in the root with no subdirectories remaining.
Still seeing Images or Documents folders?
If rmdir failed, the folders might not be empty. Run ls Images/ to check for leftover files. Move any remaining files out with mv Images/* . then try rmdir Images again.
Help me reset my messy-folder to its original state.
- Run a final count to verify your reset:
ls -1 | wc -l
You should see 15. Every file is back where it started.
Your folder is back to its messy starting point. Next up, you'll learn to chain commands together with pipes to analyze your files before automating the whole cleanup.
Chain Commands with Pipes
In the last step, you moved four files by hand and still had 11 left to deal with. Imagine if that folder had 200 files.
Pipes let you connect commands together so the output of one feeds directly into the next. This is how Linux users answer questions about their files without clicking through folders. You need this skill to figure out what your organizer script should do.
In this step, get ready to:
- Count files and filter filenames using the pipe operator.
- Extract and count file extensions with a multi-command pipeline.
- Find files matching specific patterns with the find command.
Count and filter files with pipes
A pipe (|) takes the output of the command on its left and sends it as input to the command on its right. You can chain as many commands together as you want.
- Count how many files are in your folder by running this command:
ls -1 | wc -l
What does this command do?
This chains two commands together. ls -1 lists every file on its own line. The pipe sends that list into wc -l, which counts the number of lines.
You should see 15 printed.
- Filter for files containing "mp" in their name by running:
ls -1 | grep ".mp"
You should see song.mp3 and video.mp4 listed. The grep command filtered the list down to only filenames containing that pattern.
Seeing zero results or an error?
Make sure you are still in the ~/messy-folder directory. Run pwd to check. If you are somewhere else, run cd ~/messy-folder to get back.
Also make sure the pipe character is | (Shift + backslash on most keyboards), not a lowercase L or the number 1.
Help me troubleshoot my pipe commands
Extract and count file extensions
You can chain more than two commands. Each pipe passes its output to the next command in line, building up a more powerful query step by step.
- Before you run the next command, think about this: how many different file extensions do you have in your folder, and which one appears most often?
- Build a pipeline to extract and count every file extension by running:
ls -1 | rev | cut -d. -f1 | rev | sort | uniq -c | sort -rn
You should see a count of files per extension, sorted from most to least common. Something like 2 jpg and 1 mp3 in the output.
What does this pipeline do?
- ls -1 lists every file on its own line.
- rev reverses each filename (so photo.jpg becomes gpj.otohp).
- cut -d. -f1 cuts at the dot and takes the first field (the reversed extension).
- rev reverses it back to normal (gpj becomes jpg).
- sort puts extensions in alphabetical order so duplicates sit together.
- uniq -c counts how many times each unique extension appears.
- sort -rn sorts the counts from highest to lowest.
You now know exactly what file types you have and how many of each. This is the information your organizer script will need.
Find files matching specific patterns
The find command searches for files matching specific criteria. Combined with -name patterns, this is how scripts locate files to move.
- Find all the code-related files in your folder by running:
find . -maxdepth 1 -type f -name "*.js" -o -name "*.css" -o -name "*.html"
What does this command do?
- find . searches in the current directory.
- -maxdepth 1 stops it from looking inside subdirectories.
- -type f limits results to files only (not directories).
- -name "*.js" -o -name "*.css" -o -name "*.html" matches files ending in those extensions. The -o means "or".
You should see ./app.js, ./style.css, and ./index.html listed. This is exactly how your script will identify which files belong in which category.
Not seeing all three files?
Make sure each -name pattern is wrapped in quotes. Without quotes, the shell may expand the * wildcard before find gets it.
Also check that you typed -o (the letter o, for "or") between each -name pattern. Without -o, find treats conditions as "and" and returns nothing.
Help me fix my find command
You now have the building blocks. You can count files, sort them by type, and find files matching patterns. In the next step, you will bundle all of this into a single script that does the organizing for you automatically.
Write the Organizer Script
You now know the commands and patterns. You can navigate folders, move files, and chain commands together with pipes to analyze your file collection.
A Bash script is a text file full of commands that Linux runs in sequence. In this step, you'll bundle everything you've learned into a single reusable tool called organizer.sh that does in one second what took you minutes by hand.
In this step, get ready to:
- Create a Bash script file using the nano editor and make it executable.
- Run the script to organize all 15 files into category folders.
- Verify that every file landed in the right place.
Create the script file in nano
The nano text editor is pre-installed on Ubuntu. It shows keyboard shortcuts at the bottom of the screen, so you don't need to memorize anything.
- Open a new file called organizer.sh in nano by running this command:
nano organizer.sh
Your terminal is now inside the nano editor. You'll type the script in four sections below, one after the other. Do not close nano until all four sections are entered.
- Type this first section into nano. This is the script setup:
#!/bin/bash
TARGET_DIR="${1:-.}"
if [ ! -d "$TARGET_DIR" ]; then
echo "Error: $TARGET_DIR is not a directory."
exit 1
fi
cd "$TARGET_DIR" || exit 1
shopt -s nullglob
moved=0
skipped=0
What does this section do?
- #!/bin/bash is the shebang line. It tells Linux to run this file using Bash.
- TARGET_DIR="${1:-.}" accepts an optional folder argument. If none is given, it defaults to the current directory (.).
- The if block validates that the target is actually a directory before proceeding.
- shopt -s nullglob prevents the loop from running on a literal * string if the folder is empty.
- moved and skipped are counters that track what the script does.
- Directly below what you just typed, continue with the for loop and extension extraction:
for file in *; do
[ -f "$file" ] || continue
filename="$file"
ext="${filename##*.}"
if [ "$ext" = "$filename" ]; then
ext=""
fi
ext_lower=$(echo "$ext" | tr '[:upper:]' '[:lower:]')
What does this section do?
- for file in * loops over every item in the directory.
- [ -f "$file" ] || continue skips anything that isn't a regular file (like directories).
- ${filename##*.} uses parameter expansion to strip everything up to the last dot, leaving just the extension.
- The if check handles files with no extension. If the extension equals the full filename, there was no dot.
- tr '[:upper:]' '[:lower:]' converts the extension to lowercase so .JPG and .jpg match the same category.
- Continue typing the case statement that maps extensions to category folders:
case "$ext_lower" in
jpg|jpeg|png|gif|svg)
category="Images"
;;
pdf|doc|docx|txt|odt)
category="Documents"
;;
mp3|wav|flac|ogg)
category="Audio"
;;
mp4|avi|mov|mkv)
category="Video"
;;
sh|py|js|html|css)
category="Code"
;;
zip|tar|gz|7z)
category="Archives"
;;
*)
category="Other"
;;
esac
What does the case statement do?
A case statement is Bash's version of a multi-branch if/else. Each pattern group (separated by |) matches one or more extensions and assigns a category name. The *) at the bottom is the catch-all for anything that doesn't match.
Six categories cover the most common file types. Anything unrecognized goes to Other.
- Finish the script by typing the move logic and summary output:
mkdir -p "$category"
if [ ! -e "$category/$file" ]; then
mv "$file" "$category/"
echo "Moved: $file -> $category/"
((moved++))
else
echo "Skipped (exists): $file"
((skipped++))
fi
done
echo ""
echo "Done! Moved: $moved, Skipped: $skipped"
What does this section do?
- mkdir -p "$category" creates the category folder if it doesn't exist yet. The -p flag means no error if it already exists.
- The if [ ! -e ... ] check prevents overwriting a file if one with the same name is already in the target folder.
- Each move prints a confirmation line so you can watch the script work in real time.
- done closes the for loop. The final two lines print a blank line and a summary of totals.
Save the file and make it executable
- Save the file by pressing Ctrl+O, then press Enter to confirm the filename.
- Exit nano by pressing Ctrl+X.
- Make the script executable by running this command:
chmod +x organizer.sh
- Confirm the file exists and has the right permissions by running:
ls -l organizer.sh
You should see organizer.sh listed with -rwxr-xr-x permissions. The x characters mean the file is now executable.
Don't see the x in permissions?
Make sure you ran chmod +x organizer.sh (with a space between +x and the filename). If you see -rw-r--r-- without any x, run the chmod command again.
If nano didn't save properly, run cat organizer.sh to check the file has content. An empty file means nano closed without saving.
Help me debug my permissions issue.
✔️ Awesome, I've got everything!
Great. Make sure organizer.sh is saved and executable before continuing.
ⓧ I'd like to double check the full code
Your organizer.sh file should contain all four sections you typed above, in order:
- Section 1: Shebang, TARGET_DIR, directory validation, cd, shopt, and counters.
- Section 2: The for loop opening, file check, extension extraction, and lowercase conversion.
- Section 3: The full case statement with all seven categories (Images, Documents, Audio, Video, Code, Archives, Other).
- Section 4: mkdir, the duplicate check with mv, echo confirmations, done, and the summary line.
Run cat organizer.sh to print the file and scroll up to compare each section with the code blocks above.
Run the organizer script
Before you run this, think about what you expect to happen. The script loops through every file, detects its extension, and moves it into a category folder. What will happen to organizer.sh itself?
- Run the script by executing this command:
./organizer.sh
You should see a line printed for each file as it moves, followed by a summary at the end.
Why did the script move itself?
The script has a .sh extension, and the case statement maps .sh to the Code category. The script treats itself like any other file. Linux lets a running script be moved because the kernel keeps it in memory until it finishes executing.
This is expected behavior. In the Secret Mission, you'll learn how to exclude specific files from processing.
Seeing "Permission denied"?
This means the execute permission wasn't set. Run chmod +x organizer.sh and try again. If you get "No such file or directory", check you're in the right folder with pwd. It should show ~/messy-folder.
If you see a syntax error, run bash -n organizer.sh to check for typos. This command validates the script without running it.
Help me debug my organizer script.
Verify the results
- See what's inside each category folder by running:
ls */
You should see each folder listed with its contents, similar to this:
Archives/:
backup.zip data.tar
Audio/:
podcast.wav song.mp3
Code/:
app.js index.html organizer.sh style.css
Documents/:
notes.txt readme.doc report.pdf
Images/:
logo.svg photo.jpg screenshot.png
Video/:
clip.mov video.mp4
- Confirm no loose files remain in the root by running:
find . -maxdepth 1 -type f | wc -l
The output should be 0. Every file, including the script itself, has been sorted into a category folder.
Still seeing files in the root?
If find returns a number greater than 0, run ls -la to see what's left. Common causes:
- A typo in the case statement means an extension wasn't recognized. Check that ;; terminates every case pattern.
- A missing * catch-all at the end of the case statement leaves unmatched files behind.
Help me figure out why files remain after running my script.
Your organizer works. Fifteen scattered files are now neatly sorted into labeled folders with a single command. Next up in the Secret Mission, you'll add logging and handle edge cases to make this script production-ready.
Secret mission
Add Logging and Handle Edge Cases
Your script organizes files, but what happens when things go wrong? Can it handle files with no extension? Does it leave any record of what it did? Time to find out.
Clean Up Your Resources
Clean Up Your Resources
Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project runs entirely locally on WSL, so there are no ongoing costs.
Resources you used:
- WSL with Ubuntu installation (~1-2 GB disk space).
- The ~/messy-folder directory containing your organizer script, category folders, and log file.
Keep everything running
No action needed. Choose this if you want to keep practicing Linux commands or reuse your organizer script.
- WSL uses almost no resources when idle. You can open Ubuntu anytime from the Start menu to keep practicing.
- Your organizer.sh script stays in ~/messy-folder and is ready to use on any directory.
Pause - I'll come back to this later
Close the Ubuntu window to free up memory. WSL sleeps automatically when no terminal is open.
- Close the Ubuntu terminal window.
- WSL enters an idle state on its own. No manual shutdown needed.
- To resume later, open Ubuntu from the Start menu. Your files and script will still be there.
Delete - I don't want to use this again
Remove all project files and the Ubuntu installation entirely. You can always reinstall later with wsl --install.
- Open PowerShell as Administrator.
- Remove the Ubuntu distribution and all its data (including your ~/messy-folder and script) by running:
wsl --unregister Ubuntu
- To also disable the WSL feature on Windows, search for Turn Windows features on or off in the Start menu.
- Uncheck Windows Subsystem for Linux and click OK.
- Restart your computer when prompted.
Nice Work!
Nice Work!
You just built a working Bash script that organizes a messy folder in under a second. You went from zero Linux experience to writing shell automation on a real Ubuntu environment running right on your Windows machine.
You've learned how to:
- Set up a full Linux environment on Windows using WSL and Ubuntu, giving you a real terminal to practice in.
- Navigate, create, inspect, and move files using essential commands like cd, ls, mkdir, mv, and find, then chain them together with pipes to answer questions about your files.
- Write a complete Bash script (organizer.sh) that automatically sorts files into categorized folders using variables, loops, conditionals, and case statements.
- Secret Mission: Added timestamped logging and handled edge-case files with no extension.
Ready to quiz yourself?