5

I'm a WSL convert, coming from cygwin. One of the neat things cygwin does is accept unix and Windows file paths in the cd command. Of course, most Windows paths contain \, which is a special character in unix, but so long as you escape it, cding to Windows paths works as expected: cd 'C:\Program Files' will Change your Directory to /cygdrive/c/Program Files1.

This isn't the case for WSL. cd 'C:\Program Files' prints an error message: cd: no such file or directory: C:\Program Files.

I like the cygwin functionality. Is there a way of getting the same behavior when I use cd in WSL?

The solution could come in the form of installing a 3rd party tool (i.e., sudo apt install <x>), creating an alias, enabling some bind or bindkey in my shell, or writing my own shell script. So long as it allows me to use unix and Windows paths as a cd argument, I'll be happy.


Additional information

My distro is Ubuntu. I use zsh as my main shell but write shell scripts in bash. Ideally, the solution would work for both, but if that's not possible, I'd want a zsh solution.

I found this related question that may help people trying to answer mine: Cygwin: CD to Windows paths easily

For those that don't use WSL but would like to help, it's worth knowing that WSL comes with a command named wslpath. This is the closest thing I've found to official documentation, and this is its usage output:

➜  ~ wslpath
wslpath: Invalid argument
Usage:
    -a    force result to absolute path format
    -u    translate from a Windows path to a WSL path (default)
    -w    translate from a WSL path to a Windows path
    -m    translate from a WSL path to a Windows path, with '/' instead of '\'

EX: wslpath 'c:\users'

I'm already using this command in another script I wrote to open a directory/file in Windows from the WSL command line:

➜  ~ cat ~/bin/open
#! /bin/bash
set -x

arg="$*"
explorer.exe "$(wslpath -w "$arg")" # take a unix path and open it in Windows

1: cygwin's /cygdrive/c/ path is synonymous with WSL's /mnt/c path.

4 Answers 4

5

Cygwin emulates Unix/Linux library interfaces on top of Windows library interfaces. It takes pains to make Unix cohabit with Windows, and in particular converts paths to Windows paths inside basic library functions that handle file names. That code is specific to Cygwin, designed to make most Unix-like programs work in a Windows environment. So when that code sees a path like c:\somefile, it leaves it untranslated, rather than attempting to open a file called c:\somefile in the current directory.

WSL aims to provide a complete Linux environment that runs inside a Windows system rather than running directly on top of hardware. It takes pains to make Linux programs work, including supporting colons in file names. So when that code sees a path like c:\somefile, it makes sure that this is treated as c:\somefile in the current directory.

For this reason, WSL programs cannot, in general, support Windows paths. Access to UNC paths is possible, but requires mounting.

You can, however, add translation code for specific commands, if you don't mind that they will not support edge cases such as certain file names containing colons or backslashes.

To customize the cd command, which is a shell builtin, write your own function that does whatever it wants before calling the shell builtin. Here's untested code for your .zshrc which recognizes a Windows path when cd is called with a single argument:

function cd {
  emulate -L zsh
  if [[ $# -eq 1 && ( $1 == [A-Za-z]:\\* || $1 == \\\\*\\* ) ]]; then
    set -- "$(wslpath "$1")"
  fi
  builtin cd "$@"
}

Note that if the path contains spaces or other special characters, it needs to be quoted. In particular, you can't just paste an arbitrary path after cd . (If the only special characters are single spaces, you can concatenate the arguments. But that can't work, for example, with a path containing two consecutive spaces.) To change to the directory whose path is in the clipboard, use something like

alias cdp='cd "$(powershell.exe -c Get-Clipboard)"'
1
  • I think I'm going to look into your answer before Stephane's because I'm more familiar with the code you're using. Thank you! Commented Dec 27, 2023 at 21:54
3

If it's only cd/pushd zsh builtins you want to recognise Windows-like paths, you could redefine them as:

cd pushd() {
  emulate -L zsh
  set -o extendedglob
  local match
  if [[ $argv[-1] = (#bi)([a-z]):(|[\\/]*) ]] argv[-1]=/mnt/$match[1]:l$match[2]:gs:\\:/
  builtin $0 "$@"
}
5
  • Interesting... There's something for me to research on every line here. man emulate/set/local/builtin all say "No manual entry for x", but I'll do my best to research them on my own. The one thing I probably need help with is that if statement line. It looks like a regex, and I'm familiar with the concept, but I might be completely wrong about that assumption. Would you mind explaining what it does and how it does it? Commented Dec 21, 2023 at 21:10
  • Sorry for not putting this in my original question, but I've added a description of the wslpath command. I think it has the potential to significantly simplify your answer. Commented Dec 21, 2023 at 21:34
  • 2
    @DanielKaplan These are zsh built-ins so the man page is man zshbuiltins, but it's nicer to read the same documentation in HTML. [1/2] Commented Dec 23, 2023 at 21:06
  • 2
    @DanielKaplan The thing on the right of the equal sign inside the double brackets is a glob, which is a regular expression in a different syntax from the common one. The part after argv[-1]= uses fancy parameter expansion including history modifiers. [2/2] Commented Dec 23, 2023 at 21:07
  • @Gilles'SO-stopbeingevil' oh wow. I had no idea glob patterns had a way of specifying flags. Thank you! Commented Dec 27, 2023 at 21:52
2

This isn't possible. On Unix, cd is built into the shell (it has to be in order to work). The zsh and bash you use are shipped from Ubuntu and will be identical to the ones on a real Linux system.

Unix systems will treat this as a single relative directory; that is, doing cd 'C:\Program Files' will look for a directory under the current one called C:\Program Files, which is a valid simple path component on Unix. (I should point out that this is not a valid simple directory or path component on Windows.) So what you're asking for on WSL is different than what you're asking for on Linux.

If your question is, “Why doesn't Ubuntu in WSL have this special case?” then the answer is that Ubuntu and other Linux distros are not in the business of shipping WSL distributions, they're in the business of shipping real Linux systems, and having weird Windows-specific behaviour in their code is a huge maintenance burden (you can see this in the amount of work to maintain tools in Git for Windows or Cygwin).

In addition, people working under WSL usually want things to work identically to Linux, and every departure from that would be considered a bug. Just because you do not want to refer to a directory under the current one with a weird pathname containing a colon and backslash does not mean other people won't, and lots of Unix tools have tests and assumptions that at the very least, arbitrary non-slash, non-NUL UTF-8 can be stored in the file system, so making this change would break a lot of Unix tools.

2
  • This isn't possible. I'm not trying to stir up anything by asking this, but doesn't that contradict Stephane's answer? Commented Dec 21, 2023 at 21:05
  • re: my comment above, I think I should have clarified my question better. I'm not trying to modify the "WSL cd command," I'm trying to get different behavior when I run the cd command in the terminal and shell scripts. Commented Dec 27, 2023 at 21:47
0

I just use /mnt/(drive name)/Windows/path/to.

For example, if I wanted to change into the Windows path D:\test, then I'd write cd /mnt/d/test when using WSL.

1
  • Thank you, Caleb. Indeed that is a way to cd to windows path, but my question is about passing a windows path to WSL's cd command. e.g., I want cd 'D:\test' to put me in /mnt/d/test. Commented Mar 18 at 19:58

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .