WSL: everyday work and gotchas
Where to keep your files, why a project in a Windows folder is slow, how to open the code in an editor, and what to do about permissions.
You've already installed WSL. Next come the questions you run into in the first week: where to
keep a project, why git status thinks for five seconds, how to open code in an editor, and where
that required file not found error on a script that is definitely on disk comes from.
Why this matters
Almost every beginner problem in WSL comes from one place. Two operating systems live side by side,
each with its own file system, permissions, and line endings. As long as you keep them separate in
your head, everything works. Mix them up, and you get slowdowns, a chmod that "disappears," and
scripts that won't run.
Two file systems
After installing, you have two different storage areas.
The Linux file system lives inside WSL. Its home directory is /home/<name>, also ~. It's a fast
disk, with real permissions.
Windows drives are mounted under /mnt. Drive C: shows up as /mnt/c, drive D: as /mnt/d.
You can read and write there, but it comes at a cost. If you see /mnt/ in a path, you're working
on a Windows drive.
pwd
/home/anna
Keep projects in Linux, not in /mnt/c
Access to /mnt/c goes through a layer between Linux and Windows. On a single file the difference
is invisible. On a project with thousands of small files it turns into torture: git status thinks
for seconds, installing dependencies takes much longer, builds barely crawl. Microsoft's own docs
recommend it plainly: if you work in a Linux terminal, keep the files on the WSL file system.
Keep your working files in ~:
mkdir -p ~/projects
cd ~/projects
git clone https://github.com/<owner>/<repo>.git
Leave /mnt/c for exchange: grabbing a downloaded file from "Downloads", putting a report on the
desktop.
cp /mnt/c/Users/<windows_name>/Downloads/report.pdf ~/
Reaching Linux files from Windows
Files inside Linux aren't hidden. The fastest way to open the current folder in File Explorer:
explorer.exe .
The trailing dot is required: it means "the current folder". You can also type \\wsl$ into File
Explorer's address bar (on newer Windows builds the same thing lives at \\wsl.localhost). You'll
find every installed distro there, then a path like \\wsl$\Ubuntu\home\<name>. You can pin the
folder to "Quick access".
Editor
You don't need to install an editor inside Linux. VS Code can work this way: the window stays in Windows, and all the work happens inside WSL.
Install VS Code on Windows and the WSL extension (ms-vscode-remote.remote-wsl). Then from a WSL
terminal, inside the project folder:
code .
On first launch, VS Code downloads its server component into WSL. A label like WSL: Ubuntu
appears in the bottom-left corner of the window. It means the built-in terminal, debugger, and
extensions are running on the Linux side.
Permissions on Windows drives
Files on /mnt/c don't have permissions in the usual sense. Windows keeps access its own way, and
by default WSL translates the Windows user's permissions into rwx bits, the same for owner,
group, and others. In your own folders, where you have full access, that shows up as -rwxrwxrwx
on every file.
Here's the catch: chmod on drive C does nothing by default. The command runs without an error,
but ls -l shows the same permissions as before it. The one exception: if you remove all write
permissions from a file, Windows sets its "Read-only" attribute.
Real permissions on /mnt/c turn on with the metadata option in /etc/wsl.conf:
[automount]
options = "metadata"
After that you need to restart WSL (wsl --shutdown from PowerShell). It's simpler and more
reliable to keep projects in ~: permissions are real there, and git sees them the way it should.
This matters for git too. If you ran chmod +x deploy.sh in ~, git records the file in the
commit with mode 100755, and the script stays executable for your colleagues too. On /mnt/c
there's no such guarantee.
Line endings
Windows ends a line with two characters, \r\n (CRLF), Linux with one, \n (LF). Open a script in
a Windows editor, save it, and an extra \r shows up at the end of every line.
For shell scripts this breaks everything. The line #!/bin/bash turns into #!/bin/bash\r, and the
system looks for an interpreter with that exact name. The error text depends on where and how you
run it:
bash: ./deploy.sh: cannot execute: required file not found
That's what bash 5.2 on Ubuntu 24.04 prints. Older bash (3.2 on macOS, for example) is clearer:
bash: ./deploy.sh: /bin/bash^M: bad interpreter: No such file or directory
^M here is the \r. And if the first line is #!/usr/bin/env bash, the error is about env:
/usr/bin/env: 'bash\r': No such file or directory
Running it as bash deploy.sh skips the first line, but \r stays at the end of every command and
every value. The script seems to work, yet creates folders with an invisible character in the name.
That's worse than a plain error.
You can see the \r in a file like this:
od -c deploy.sh | head -3
0000000 # ! / b i n / b a s h \r \n e c h
...
To remove \r, use the dos2unix utility (installed separately, sudo apt install dos2unix) or
the standard tr, which strips characters from a stream. Keep in mind that if the new file is written
next to the old one and then renamed over it, it'll have its own execute bit, not the old one's.
How git helps with line endings
To keep CRLF out of the repo entirely, you set up git once in WSL:
git config --global core.autocrlf input
With input, git turns CRLF into LF in what goes into the commit on git add, and adds nothing
when checking files out. The catch: the file in the working copy doesn't change. git only warns:
warning: in the working copy of 'deploy.sh', CRLF will be replaced by LF the next time Git touches it
The script in the working copy stays broken until you fix it yourself or check it out again from the commit.
The core.autocrlf setting lives on your machine. For the rule to work for the whole team, it goes
into the repo, in a .gitattributes file:
*.sh text eol=lf
This line tells git: .sh files are text, they always get LF in the working copy, no matter who
checks the repo out. To check which rule applies to a file, run git check-attr eol -- <file>.
How much memory WSL takes
WSL2 runs in a virtual machine and by default can use up to half of the Windows RAM. If Windows starts
lagging, rein it in. Create a file on Windows at C:\Users\<name>\.wslconfig (that's
%UserProfile%\.wslconfig):
[wsl2]
memory=4GB
processors=2
Then restart the subsystem from PowerShell:
wsl --shutdown
The settings apply only once the WSL virtual machine has fully stopped. Just closing the terminal
window leaves it running for about 8 more seconds, so wsl --shutdown is more reliable. You can
change the same thing in the "WSL Settings" app from the Start menu.
systemd
Many tutorials online assume systemd, meaning commands like systemctl start docker. In the current
Ubuntu that wsl --install sets up, systemd is already on. Check it:
systemctl status
If systemctl doesn't list services and instead complains that the system wasn't started with
systemd, your distro is a different or older one. Then open /etc/wsl.conf with sudo nano /etc/wsl.conf
and add:
[boot]
systemd=true
Then wsl --shutdown from PowerShell and start it again.
Common mistakes
- The project was cloned into
/mnt/c/Users/.... Symptom: everything is slow,chmodhas no effect. Move the project to~. - A script was saved in Notepad or an editor set to CRLF. Symptom:
required file not foundorbad interpreterfor a file that's definitely there. Check withod -c. core.autocrlf inputwas turned on, but the broken script is still there. The setting doesn't touch the working copy..wslconfigorwsl.confwas edited, the window was closed and reopened right away. The changes don't show up: you needwsl --shutdownor an 8-second pause.\rwas removed via a new file andmv, and the execute bit got lost along the way. Symptom:Permission denied.
What you'll need for the tasks
pwd,ls -l,chmod +xod -c <file> | headto see\rtr, redirection with<and>,mvgit init,git add,git commit,git config core.autocrlf,git ls-files -s.gitattributesandgit check-attr eol -- <file>- In WSL additionally:
explorer.exe .,code .
Self-check
Type the command or key line. Case and spaces don't matter.
Done reading?
Mark the lesson as read to move your track progress forward.
Lesson marked as done.
Go through it with an AI agent
The agent explains anything unclear in plain words and walks you through 2 labs for this lesson. This track is free.
Tell the agent: use MCP izi, give me lesson wsl-setup-02-daily-work
Progress saved in this browser
Clear your history or open this on your phone, and the marks will be gone. Leave your email and they'll move to your account. No password needed.
Done. moved to your account. You can see your progress on any device. My progress