Welcome to Software Development on Codidact!
Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.
How to convert Dos paths to Posix paths in Powershell
What is the best way to convert Dos paths to Posix paths in Powershell? eg given:
C:\Program Files\PowerShell\Modules\
I want something like:
/Program\ Files/PowerShell/Modules/
Is the only solution to escape spaces and convert backslashes?
I've searched the web but couldn't find any existing Powershell function, and the solutions I found didn't mention escaping spaces, so I don't hold much hope that they're complete.
1 answer
The following users marked this post as Works for me:
User | Comment | Date |
---|---|---|
kjw |
Thread: Works for me Such a great answer, collates a lot of info into a single place. On top of that, of the potential solutions: multiple of them work for me, and am now a... |
Aug 31, 2023 at 01:10 |
TL;DR: Use wslpath
and hope for the best.
You can use it like this in Powershell: wsl wslpath -u 'C:\\some\\path\\to\\folder\\or\\file.txt'
Long answer
Converting them is hard. There is windows tool wslpath
for Windows with WSL, but that may not work in every case. There is also winepath
which is for Linux systems with wine installed. Both take advantage that there is a unixlike and a Windowslike system installed that can both access the same file and this tools have the needed information where this files are.
But there are a lot of problems you can run into and wslpath
will not always solve all of them.
Slashes vs backslash
Windows accepts \
as separator in paths. In Posix paths \
is just a "normal" character. You have to convert all \
to /
. This is probably the easiest part.
Something wslpath
and winepath
should be able to do without any problem.
Drive letters
Windows absolute paths start with a partition letter. In Posix, all files are under /
. So it is impossible to convert a absolute path without some knowledge about the system you are running on.
wslpath
and winepath
should be able to do this without any problem for the current system they are running on. But when you move to a different system, the paths maybe no longer valid.
Limits of Posix filenames
Posix accepts any character (means any byte value) in filenames except '/' and '\0'
/ NUL
. The limits you have are: The maximum length of file or folder name, the maximum length of a path. No file with the name .
(current folder) nor ..
(parent folder) and a filename needs to have at least 1 character.
There can be however additional limits of the underlying filesystem or NAS-Server.
So there is no problem in this regard for converting from Windows to Posix filenames, but it can be a problem for the other way around.
Spaces in Filenames
Posix and Windows accept spaces in filenames without any problem. Both don't need any special treatment on a kernel or syscall level.
However, a shell, such as bash, may split a string by spaces to create a list of arguments. This is done in the bash application / program and doesn't touch the kernel or the underlying filesystem. To prevent a shell such as bash splitting a string into spaces you can either escape the spaces. For example:
myCommand this\ is\ a\ single\ argument\ to\ myCommand
Or by putting quotes around it, which is probably the simplest solution:
myCommand "this is also a single argument to myCommand"
myCommand 'this too'
Note that this isn't only the case in Posixlike system, but cmd.exe
from Windows also needs to use quotes around paths that have spaces.
There is no conversation problem to be expected in this regard.
Encoding
Windows NT (the kernel, not just the Windows OS version) uses UTF-16. AFAIK Posix doesn't require a specific encoding, but it has to be a 8bit encoding. But most modern unixlike systems use UTF-8. You can solve 98% of the problems when you just convert UTF-16 to UTF-8.
The kernel needs to care about encoding as soon as you mount a filesystem with a kernelspace driver that doesn't use the same byte values. For example, when you mount a NTFS drive, the driver has to convert 16 bit characters to a stream of 8 bit bytes and vice versa. On Linux you can specify how this is done with the iocharset
mount option.
However, be aware that there can be more problems, depending on what level of compatibility you need. For example some buggy software may converted UCS-2 to CESU-8 or a very old software may use iso8859-1 for 8bit encoding.
Case insensitivity
Windows converts some of the characters case before comparing filename. I don't know the rules when this is done and how. (This may sound simple but comparing case insensitive is a very difficult task that has a lot of cases that need to be defined in a non-obvious way).
This can be a problem when you rename something on Windows in a way that old paths to that file will still work unchanged even when the name is different. On Posix, the new name will be a different file.
For example, you have this files:
Windows: C:\my\path\to\file.txt
Posix: /my/path/to/file.txt
And after renaming you have
Windows: C:\My\Path\to\FILE.txt
Posix: /My/Path/to/FILE.txt
The Windows paths C:\my\path\to\file.txt
and C:\My\Path\to\FILE.txt
are equvivalent and point to the same file. On Posix, /my/path/to/file.txt
and /My/Path/to/FILE.txt
are different paths and most likely different files.
If you know how to convert between the cases in the exact way Windows does it, you can convert all files to lowercase or UPPERCASE. But is that what the user expects? And you have to know the case changing function never changes (which is hard given that this is a complex task and that new letters and new language rules maybe invented in the future).
I don't want to go into all the details of converting cases, since this has a long list of edge cases, information loss, undefined cases and more that makes that a very difficult task. But you will have to deal with it when you want to create a 1:1 mapping between Posix filenames and Windows filenames.
wslpath
will give you the correct filename at the time of running, but when you rename the file later, it maybe no longer valid in Posix and WSL maybe not be able to access it with the same path while the path on Windows still works.
8.3 filename
On windows all files with a name longer than 8+3 characters have a 8.3 shortcut. If you want to convert them correctly, you may have to expand them.
Special files
On Windows ./NUL
is a special file, and so is ./CON
and even C:\thisFolderExist\CON
but not C:\thisFolderDoesNotExist\CON
. This files: ./CON
, C:\thisFolderExist\CON
do map to /dev/tty
on some (all?) posixlike systems, but C:\thisFolderDoesNotExist\CON
does not map to any file.
The question is if you care. Best approach is probably checking if the basename is a special file and if it is, generate some form of error.
Universal Naming Convention
Windows allows to specify a path using their Universal Naming Convention (UNC). This starts with \\
and can hold a path to the local machine or it can contain a server address. A local path may look like this \\?\C:\SomeFolder\file.txt
. If you want to convert this as well, you need to check for such paths.
A equivalent that exist on some applications for unixlike systems would be a URL, which also can hold a path to a local machine like this file:///SomeFolder/file.txt
, however most applications will probably not support this and most (all?) kernels also don't support that.
2 comment threads