Cached at:
09/14/26, 09:05 PM
# How I use a single .zshrc file on macOS and Windows (WSL2)
Source: [https://talkoren.com/blog/single-zshrc-macos-windows-wsl2](https://talkoren.com/blog/single-zshrc-macos-windows-wsl2)
Ever since The Matrix came out in 1999, I've been into command line interfaces\. The feeling of knowing how to navigate your way around verbose interfaces has its magic \(which is also part of the reason why I like CSS, vim and RegEx\)\.
Today I have 3 machines \- my personal MacBook Pro, and two desktop Windows gaming PCs \(long story, don't ask\)\. Being the CLI geek that I am, I started playing around with WSL back in 2016 \(and afterwards WSL2, which runs an actual Linux kernel inside a lightweight virtual machine\)\.
Since then I've been a huge Z shell \(zsh\) user, and I use it across all my machines\. I'm using[chezmoi](https://chezmoi.io/)to manage my dotfiles, and \.zshrc among them\.
Using zsh on WSL and macOS may seem trivial because both give me a Unix\-like environment, but there are some differences when it comes to core OS behavior, like using ssh or having convenience commands like`open`\. Therefore, maintaining separate`\.zshrc\.mac`and`\.zshrc\.wsl`files would inevitably make them drift apart, and as a developer with ADHD, I know it's just a matter of time until I update one and forget the other\. Hence my rule for managing this was to have a file that's shared by default, and conditional when the OS actually matters\.
## Cutting to the chase
First, I need to know whether the shell is running inside WSL:
```
if grep -qi microsoft /proc/version 2>/dev/null; then
IS_WSL=1
fi
```
I set the`IS\_WSL`variable to distinguish between the operating systems\. The`q`flag is for quiet \(we don't want the`grep`output to print every time a shell starts\), and`i`makes the check case\-insensitive, so it does not depend on how Microsoft is capitalized\.
On macOS,`/proc/version`doesn't exist, but the error is redirected to`/dev/null`, so the condition simply fails\.
## SSH
I use the 1Password ssh agent to avoid keeping my private keys in`~/\.ssh`\(sorry AI agents and supply chain attackers\), and it's supported in macOS, Linux, and Windows\. This distinction matters because the 1Password ssh agent runs as part of the Windows app and not inside WSL\. In my setup, WSL uses Windows' ssh client so it can talk to the 1Password agent running on Windows\.
After[configuring 1Password](https://www.1password.dev/cli/get-started#step-2-turn-on-the-1password-desktop-app-integration)to enable me to use their CLI and configuring the[ssh agent](https://www.1password.dev/ssh/agent), all I had to do was:
```
if [ "$IS_WSL" = 1 ]; then
alias ssh='ssh.exe'
alias ssh-add='ssh-add.exe'
fi
```
This works, but there's a slight issue with git here \- the`ssh`alias only exists inside my interactive zsh session\. When Git launches ssh itself, that alias isn't involved, so I also need to set[`GIT\_SSH\_COMMAND`](https://git-scm.com/docs/git#Documentation/git.txt-GITSSHCOMMAND)to ssh\.exe\. The same is true for`scp`\.
The resulting conditional in that case, is:
```
if [ "$IS_WSL" = 1 ]; then
alias ssh='ssh.exe'
alias ssh-add='ssh-add.exe'
alias scp='scp.exe'
export GIT_SSH_COMMAND='ssh.exe'
fi
```
Now I can handle all ssh\-related operations across macOS and WSL\.
## Using Finder and Explorer
On macOS,`open \.`opens the current directory in Finder\. In WSL,`explorer\.exe \.`does roughly the same thing in Windows Explorer\. You see where this is going\.\.\.
Since`open`is already a system command on macOS, I only need to overwrite it when using WSL on Windows:
```
open() {
explorer.exe "$(wslpath -w "${1:-.}")" 2>/dev/null
}
```
`wslpath \-w`converts the WSL path to Windows format, while`$\{1:\-\.\}`defaults to the current directory if no path is provided\.
And since this is irrelevant to macOS, it makes sense to only set it under WSL, making our conditional:
```
if [ "$IS_WSL" = 1 ]; then
alias ssh='ssh.exe'
alias ssh-add='ssh-add.exe'
alias scp='scp.exe'
export GIT_SSH_COMMAND='ssh.exe'
open() {
explorer.exe "$(wslpath -w "${1:-.}")" 2>/dev/null
}
fi
```
## Simplicity equals sanity
The result is one \.zshrc that behaves like a native configuration on both systems\. Most of it stays shared, and the handful of Windows\-specific differences remain visible in one small conditional\. Predictable, readable, and sane to maintain \(mainsane?\)\.