Skip to content

Instantly share code, notes, and snippets.

@lamyj
Last active February 20, 2024 22:35
Show Gist options
  • Save lamyj/f311c98e8939fd5a46c8e2420364dc35 to your computer and use it in GitHub Desktop.
Save lamyj/f311c98e8939fd5a46c8e2420364dc35 to your computer and use it in GitHub Desktop.
Convert between Windows path and Linux path in WSL
#!/usr/bin/env python
from __future__ import print_function
import argparse
import json
import re
import subprocess
import sys
def main():
parser = argparse.ArgumentParser(
description=(
"Convert between Linux and Windows paths in WSL. "
"If no converter is explicitely specified, an implicit one is "
"deduced."))
parser.add_argument("path", metavar="PATH")
group = parser.add_mutually_exclusive_group()
group.add_argument(
"-w", action="store_true",
help=(
"Print the Windows path equivalent to PATH, "
"using backslashes"))
group.add_argument(
"-m", action="store_true",
help=(
"Print the Windows path equivalent to PATH, "
"using forward slashes in place of backslashes"))
group.add_argument(
"-u", action="store_true",
help="Print the Linux path equivalent to PATH")
arguments = parser.parse_args()
converters = [
x for x in vars(arguments)
if x in ["w", "m", "u"] and getattr(arguments, x)]
if not converters:
converter = guess_converter(arguments.path)
else:
converter = globals()["convert_{}".format(converters[0])]
print(converter(arguments.path))
def convert_w(linux_path):
""" Convert a Linux path to a Windows path. """
windows_roots = parse_mounts()[1]
linux_root = find_root(windows_roots, linux_path, "/")
linux_leaf = linux_path[len(linux_root):]
windows_root = windows_roots[linux_root]
windows_leaf = linux_leaf.replace("/", "\\")
return "".join([windows_root, windows_leaf])
def convert_m(linux_path):
""" Convert a Linux path to a Windows path with forward slashes. """
windows_roots = parse_mounts()[1]
linux_root = find_root(windows_roots, linux_path, "/")
linux_leaf = linux_path[len(linux_root):]
windows_root = windows_roots[linux_root]
return "".join([windows_root, linux_leaf])
def convert_u(windows_path):
""" Convert an absolute Windows path to a Linux path. """
linux_roots = parse_mounts()[0]
windows_root = find_root(linux_roots, windows_path, "\\")
windows_leaf = windows_path[len(windows_root):]
if not windows_leaf.startswith("\\"):
raise Exception("Cannot convert relative Windows path")
linux_root = linux_roots[windows_root]
linux_leaf = windows_leaf.replace("\\", "/")
return "".join([linux_root, linux_leaf])
def guess_converter(path):
""" Guess the best converter (to Windows with backslashes or to Linux) for
a path.
"""
if re.match(r"^[a-zA-Z]:", path):
# Drive letter and colon: Windows path
return convert_u
elif re.match(r"^\\", path):
# UNC path: convert to Linux
return convert_u
elif re.match(r"^/[^/]", path):
# Slash followed by non-slash: Linux path
return convert_w
else:
raise Exception("Could not guess converter for \"{}\"".format(path))
def parse_mounts():
""" Return a map of Windows roots to their corresponding Linux root and a
map of Linux roots to their corresponding Windows root.
>>> linux_roots, windows_roots = parse_mounts()
>>> linux_roots["C:"]
'/mnt/c'
>>> windows_roots["/mnt/c"]
'C:'
"""
# Map a Windows root to a Linux root
linux_roots = {}
# Map a Linux root to a Windows root
windows_roots = {}
data = subprocess.check_output(["findmnt", "-J", "-l", "-t", "drvfs"])
data = json.loads(data)
for filesystem in data["filesystems"]:
linux_path, windows_path = filesystem["target"], filesystem["source"]
linux_roots[windows_path] = linux_path
windows_roots[linux_path] = windows_path
return linux_roots, windows_roots
def find_root(roots, path, separator):
""" Return the root matching the given path followed by a separator. """
candidates = [
x for x in roots
if path.startswith("{}{}".format(x, separator))]
if not candidates:
raise Exception("No root found for {}".format(path))
elif len(candidates) > 1:
raise Exception("Multiple roots found for {}".format(path))
return candidates[0]
if __name__ == "__main__":
sys.exit(main())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment