How can I convert a windows path to posix path using node path
Asked Answered
S

8

53

I'm developing on windows, but need to know how to convert a windows path (with backslashes \) into a POSIX path with forward slashes (/)?

My goal is to convert C:\repos\vue-t\tests\views\index\home.vue to C:/repos/vue-t/tests/views/index/home.vue

so I can use it in an import on a file I'm writing to the disk

const appImport = `
import Vue from "vue"
import App from '${path}'

function createApp (data) {
    const app = new Vue({
        data,
        render: h => h(App)
    })
    return app
}`

//this string is then written to the disk as a file

I'd prefer not to .replace(/\\/g, '/') the string, and would rather prefer to use a require('path') function.

Systemic answered 16/12, 2018 at 4:16 Comment(1)
what's wrong with .replace(/\\/g, '/'), I already use it in my code.Rombert
C
8

Slash converts windows backslash paths to Unix paths

Usage:

const path = require('path');
const slash = require('slash');

const str = path.join('foo', 'bar');

slash(str);
// Unix    => foo/bar
// Windows => foo/bar
Combustor answered 16/12, 2018 at 4:49 Comment(5)
Thanks, I can't upvote yet, but slash just basically .replace(/\\/g, '/')'s the stringSystemic
I don't see any API provided in the path module for this scenario.Combustor
yeah, me neither. It would be nice if it had a path.convert(myPath) optionSystemic
But it's already a one-liner in plain Node... pathstring.split(path.sep).join(path.posix.sep) and you're done, installing a module for that is kinda crazy. Especially given what github.com/sindresorhus/slash/blob/master/index.js actually does.Impetigo
OP: Does your solution handle Windows' drive designation in a path, eg C:?Cattleman
B
113

Given that all the other answers rely on installing (either way too large, or way too small) third party modules: this can also be done as a one-liner for relative paths (which you should be using 99.999% of the time already anyway) without any third party code by using Node's standard library path module, and more specifically, taking advantage of its dedicated path.posix and path.win32 namespaced properties/functions (introduced all the way back in Node v0.11):

import path from "path"; // or in legacy cjs: const path = require("path")

// Replace all "this OS's path separator", with the one you need:

const definitelyPosix = somePathString.replaceAll(path.sep, path.posix.sep);
const definitelyWindows = somePathString.replaceAll(path.sep, path.win32.sep);

This will convert your path to POSIX (or Windows) format irrespective of whether you're already on a POSIX (or Windows) compliant platform, without needing any kind of external dependency.

Or, if you don't even care about which OS you're in:

import path from "path";

const { platform } = process;
const locale = path[platform === `win32` ? `win32` : `posix`];

...

const localePath = somepath.replaceAll(path.sep, locale.sep);

But of course, you pretty much never need to specifically make a Windows path, because / has always been a valid path separator in Windows, ever since the very first windows 1.0 days. And if that's news to you as Windows user, try it right now: run cmd or powershell and type cd "/Program Files (x86)/Common Files", then hit Enter, and observe it changing dirs just fine.

The only time you'll need Windows-specific paths is for absolute paths, as Windows uses drive letters, Linux uses /dev/disk, and MacOS uses /Volumes, but 99.9% of the time that you're using absolute paths, what you actually wanted was "relative paths" tacked onto the dir that your entry point file lives in, and the other 0.1% of the time you're trying to load data over the network, using the same path syntax on every OS because that syntax depends on the network protocol you're using.

Branen answered 4/8, 2020 at 17:1 Comment(5)
Additional note: if you are dealing with a prefacing drive letter, ex. D:, you can add the following to the one liner to remove it: .substring(2)Diapause
Thanks to windows network shares, that's a dangerous assumption to make, virtually guaranteed baking bugs into your path handling. It is best not made all by sticking with relative locations (which path has several helper functions for). If your code needs to know which drive it's running on, you're already writing cross-platform incompatible code, and it's time to ask yourself why you did that.Impetigo
The code doesn't need to know what drive it is running on, path.resolve(__dirname, 'packages') returns D:/file/path/here on Windows. For what it's worth, I used the following in my actual project instead: return posixPath.replace(/^[a-zA-Z]:/, '')Diapause
Which is why you don't use resolve, you use path.join if you're composing paths, but that's all you need 99.9% of the time. In your example, for instance, you literally already have the relative path right there =)Impetigo
While I understand your point and agree with you, I have a much more complicated use case where this was required; this was a simplified example in case anyone else does as well. Thank you for your amazing answer, it was a big help!Diapause
C
8

Slash converts windows backslash paths to Unix paths

Usage:

const path = require('path');
const slash = require('slash');

const str = path.join('foo', 'bar');

slash(str);
// Unix    => foo/bar
// Windows => foo/bar
Combustor answered 16/12, 2018 at 4:49 Comment(5)
Thanks, I can't upvote yet, but slash just basically .replace(/\\/g, '/')'s the stringSystemic
I don't see any API provided in the path module for this scenario.Combustor
yeah, me neither. It would be nice if it had a path.convert(myPath) optionSystemic
But it's already a one-liner in plain Node... pathstring.split(path.sep).join(path.posix.sep) and you're done, installing a module for that is kinda crazy. Especially given what github.com/sindresorhus/slash/blob/master/index.js actually does.Impetigo
OP: Does your solution handle Windows' drive designation in a path, eg C:?Cattleman
T
5

There is node package called upath will convert windows path into unix.

upath = require('upath');

or

import * as upath from 'upath';

upath.toUnix(destination_path)
Talia answered 12/4, 2019 at 9:39 Comment(0)
G
3

For those looking for an answer that doesn't depend on Node.js

One Liner (no 3rd party library)

//
// one-liner
//
let convertPath = (windowsPath) => windowsPath.replace(/^\\\\\?\\/,"").replace(/\\/g,'\/').replace(/\/\/+/g,'\/')

//
// usage
//
convertPath("C:\\repos\\vue-t\\tests\\views\\index\\home.vue")
// >>> "C:/repos/vue-t/tests/views/index/home.vue"

//
// multi-liner (commented and compatible with really old javascript versions)
//
function convertPath(windowsPath) {
    // handle the edge-case of Window's long file names
    // See: https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#short-vs-long-names
    windowsPath = windowsPath.replace(/^\\\\\?\\/,"");

    // convert the separators, valid since both \ and / can't be in a windows filename
    windowsPath = windowsPath.replace(/\\/g,'\/');

    // compress any // or /// to be just /, which is a safe oper under POSIX
    // and prevents accidental errors caused by manually doing path1+path2
    windowsPath = windowsPath.replace(/\/\/+/g,'\/');

    return windowsPath;
};

// dont want the C: to be inluded? here's a one-liner for that too
let convertPath = (windowsPath) => windowsPath.replace(/^\\\\\?\\/,"").replace(/(?:^C:)?\\/g,'\/').replace(/\/\/+/g,'\/')

Normally I import libraries. However, I went and read the source code for both slash and upath. The functions were not particularly up to date, and incredibly small at the time I checked. In fact, this one liner actually handles more cases than the slash library. Not everyone is looking for this kind of solution, but for those that are, here it is. By coincidence this has the fastest runtime of all the current answers.

Goldsworthy answered 4/7, 2020 at 17:48 Comment(5)
This totally against modularity and efficient software development. Use ~ to pin the version of the library you are sure it works. If you use import { toUnix } from 'upath'; it only imports the needed function, so there is no runtime cost.Washing
Thats a good point @Amin, pinning the version with ~ is really useful, and should probably be used more frequently. The runtime cost is probably negligible either way, I was referring to the cost of 10 files you're adding to your node_modules. Do note though: import { aFunc } is often not zero cost. It requires 1. using a bundler 2. that bundler having tree shaking and 3. the code be be written in a way that supports being tree-shook. The vast majority of the time libraries are better than copy-paste, but this is some tiny unchanging functionality here.Goldsworthy
Why... would you do it like this, when path.sep and path.posix.sep exist? This is a one-liner already: pathstring.split(path.sep).join(path.posix.sep) and we're done. It's even cross-platform compatible.Impetigo
I actually like your answer. It doesn't handle the very rare edge case of windows long file names, and doesn't work in a browser. Also I needed the C: removed (and I'm not sure why more people wouldn't prefer that). But in general yours answers the original question in a more clean way, and is debateably the most cross platform. 👍Goldsworthy
I think you need to add more comments to this code.Imprecise
R
2

I was looking for something similar, but a little more universal especially to include drives in the absolute path. Thus if you work with e.g. git-bash or WSL usually drives are mapped by default as letters from root / (git-bash) or /mnt (WSL). So here is a regex that does the job for me

// For git-bash Windows drives are mounted in the root like /C/ /D/ etc.
const toGitBashPosixPath = (windowsPath) => windowsPath.replace(/^(\w):|\\+/g,'/$1');

console.log(toGitBashPosixPath('c:\\\\\\project\\file.x')); // messy Windows path
console.log(toGitBashPosixPath('c:\\project\\file.x')); // regular Windows path
console.log(toGitBashPosixPath('c:/project/file.x')); // slash path acceptable by Windows
console.log(toGitBashPosixPath('project\\file.x'));// relative Windows path
console.log(toGitBashPosixPath('.\\project\\file.x'));// another relative Windows path

// For WSL Windows drives are mounted by default next to /mnt like /mnt/C/ /mnt/D/ etc.
const toWSLPosixPath = (windowsPath) => windowsPath.replace(/^(\w):|\\+/g,'/$1').replace(/^\//g,'/mnt/');
console.log(toWSLPosixPath('c:\\project\\file.x'))

Hopefully this will help someone.

Ryeland answered 30/8, 2021 at 10:14 Comment(0)
T
1

Just use default lib as:

const {direname, resolve, basename}= require('path').posix;

or

import {posix} from 'path';
const {direname, resolve, basename}= posix;
Tanyatanzania answered 17/7, 2021 at 23:14 Comment(1)
Why write the same answer a year after someone else's? But then without the information that actually answer the question? As is, this should have been a comment.Impetigo
P
1

I have run a simple benchmark on various suggested solutions:

=== All 4727 files
regex: 0.925ms
mine: 13.509ms
posix: 1.658ms
slash: 1.09ms

=== One file
regex: 0.01ms
mine:  0.01ms
posix: 0.012ms
slash: 0.035ms

The solution marked as "mine" is this simple routine:

const replaceWinSlash = (path) => {
    const len = path.length;
    const out = [...path];
    for(let i=0; i < len; ++i) if(path[i] === "\\") out[i] = "/";
    return out.join("");
};

So my suggestion is to stay with a simple filePath.replaceAll("\\", "/").

Hope it helps.

Potassium answered 23/11, 2023 at 10:35 Comment(0)
J
-2
const winPath = 'C:\\repos\\vue-t\\tests\\views\\index\\home.vue'
const posixPath = winPath.replace(/\\/g, '/').slice(2)
// Now posixPath = '/repos/vue-t/tests/views/index/home.vue'
Jacquard answered 29/10, 2020 at 12:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.