13

I want to get the Windows "host" user home directory from within bash, so my theoretical environment variable (or program)

echo $WINHOME

would output something like

/mnt/c/Users/dualed

Would this be somehow possible?

When I search for it, I only find results for the opposite (finding the LXSS user path from the host)

I have a fallback-idea of extracting it from $PATH, as there are some predictable paths like those containing AppData, but I'd prefer to keep it simple, if possible.

2

10 Answers 10

13

With wslpath and wslvar:

$ wslpath "$(wslvar USERPROFILE)"
/mnt/c/Users/felipesantos
4
  • 3
    however, wslvar is not installed in WSL by default
    – hndcrftd
    Aug 1 '20 at 6:28
  • It is installed by default in Ubuntu and Ubuntu 20.04 WSL. I can't say for the others.
    – felipecrs
    Aug 2 '20 at 15:23
  • @felipecassiors I think availability is dependent on the WSL / Windows version, not on the Guest OS version, wslvar is available on my Windows 10 2004 build.
    – dualed
    Oct 24 '20 at 7:15
  • wslvar is preinstalled in the Ubuntu distro, according to github.com/wslutilities/wslu#ubuntu. I'm not sure about wslpath, though. It seems to be introduced in Windows 10 v1803: devblogs.microsoft.com/commandline/windows10v1803
    – felipecrs
    Oct 25 '20 at 18:26
5

You may launch cmd.exe from bash to get the host environment variables. In the following, win_userprofile has your answer, and the other variables are for completeness.

win_userprofile="$(cmd.exe /c "<nul set /p=%UserProfile%" 2>/dev/null)"

win_userprofile_drive="${win_userprofile%%:*}:"
userprofile_mount="$(findmnt --noheadings --first-only --output TARGET "$win_userprofile_drive")"

win_userprofile_dir="${win_userprofile#*:}"

userprofile="${userprofile_mount}${win_userprofile_dir//\\//}"

Sources : Craig Loewen at Microsoft and Michael Hoffman.

3
  • Well to be precise $win_userprofile contains the windows path, $userprofile holds the answer to my question, but yes that is pretty much what I was looking for. Though I'd prefer the translation from Windows path to Unix path to be less involved
    – dualed
    Nov 23 '17 at 21:42
  • I just found github.com/Microsoft/WSL/issues/1834#issuecomment-346443730 "Windows Insider Build 17046 contains new 'wslpath' functionality that supports path translations"
    – dualed
    Nov 23 '17 at 22:28
  • Excellent answer. I had got many of the elements of it together, but I had two problems. (1) Because I thought I might need it, I was testing in a root (sudo -s) shell, and cmd.exe wasn't in my path, so I was looking for a way to find its path; in the log-on shell this isn't necessary. (2) Although cmd.exe /c echo %userprofile% gives the path in Windows, I was struggling with complex sed filters on mount or df to map the (DriveLetter): to the Linux path; findmnt is a very neat solution. Thanks very much: I've learnt quite a lot.
    – AFH
    Nov 24 '17 at 0:18
3

Fortunately since Windows 10 build 17063 (included in Windows 10 1803) there is a more straightforward way of sharing environment variables between Windows and WSL - WSLENV.

To make %USERPROFILE% accessible in WSL you list the variable name in the WSLENV variable. If you are not using WSLENV yet then just run the following command once in a cmd.exe session. The command setx permanently writes variables to the master environment in the Windows registry:

setx WSLENV USERPROFILE/up

This WSLENV setting will cause WSL to make %USERPROFILE% from Windows accessible as $USERPROFILE in WSL shell. The Windows directory path will be converted to the Unix format. If you do not want to convert the path, just omit the p:

setx WSLENV USERPROFILE/u

If you need to transfer multiple variables separate them by a colon. More details:


I use the variable in my cdw function (cd to Windows path). I define it in ~/.bash_aliases which is executed automatically in Ubuntu:

#!/bin/bash

cdw () {
        if test "$#" -eq 0 ; then
                cd "$USERPROFILE"
        elif test "$1" = - ; then
                cd "$1"
        else
                cd -- "$(wslpath "$@")"
        fi
}
0
2

Since my writing of this question, the tool wslpath has been added to WSL/LXSS. This tool can translate windows paths to the corresponding correct (?) mount point on the Linux subsystem, therefore the easiest solution would be now:

export WINHOME=$(wslpath $(cmd.exe /C "echo %USERPROFILE%"))
# echo $WINHOME prints something like /mnt/c/Users/dualed

Also, now it seems possible to cascade environments, so this is now also an option:

export WINHOME=$(cmd.exe /C "cd /D %USERPROFILE% && bash.exe -c pwd")

PS: The wslpath tool seems extremely alpha:

man wslpath
# No manual entry for wslpath
# See 'man 7 undocumented' for help when manual pages are not available.
wslpath /?
# wslpath: /?: Invalid argument
wslpath -?
# wslpath: unrecognized option: ?
# wslpath: Invalid argument
wslpath --help
# wslpath: unrecognized option: -
# wslpath: Invalid argument
wslpath
# wslpath: Invalid argument

just a small warning.


Hopefully helpful update: Currently I'm using a small helper to retrieve windows environment variables

#!/bin/bash
# 'winenv'
cmd.exe /C "echo %$*%" | tr -d '\r'

And using it like:

WINHOME=$(wslpath "$(winenv USERPROFILE)")
2
  • wslpath isn't a tool. It is just a symbolic link (i.e. soft link ln -s) of /init file in rootfs folder.
    – Biswapriyo
    Jul 21 '18 at 19:20
  • 1
    Yes, it seems /init is the executable behind wslpath, but it acts differently when called as wslpath, so I would still call the tool wslpath and not /init and it was also announced as wslpath by the devs: github.com/Microsoft/WSL/issues/1834#issuecomment-346443730
    – dualed
    Jul 21 '18 at 20:01
1

This is my reference answer, should the question not be answerable at this time, or be unclear. It does what I wrote in the question I wanted to avoid - guessing the user's home directory by looking for fields containing AppData (and a bit more) within $PATH

#!/bin/bash
IFS=':' read -a fields <<<"$PATH"

for field in "${fields[@]}"; do
        if [[ $field =~ ^(/mnt/.*)/AppData/Local/.* ]]; then
                echo ${BASH_REMATCH[1]}
                exit
        fi
done

It does require of course that there is at least one path in %APPDATA% in Windows, and (more problematic in my opinion) that there is no AppData path set with other user names, e.g. in global scope and finally that the home directory is actually mounted in /mnt.

Example output:

$ winhome
/mnt/c/Users/dualed
1

lots of great info here! thanks. i needed an additional tweak..

when i use the cmd.exe trick in my .bash_aliases file, i get errors due to unwanted newline characters from CMD echo, which wslpath passes thru:

$ echo $(cmd.exe /C "echo %USERPROFILE%") | cat -A
C:\Users\myself^M$
               ^-- no good, wslpath turns into /mnt/c/Users/myself^M$

CMD echo does not seem to have anything like the -n option from bash echo, so borrowing from a StackOverflow post (Windows batch: echo without newline), i added a pseudo-chomp to remove them:

$ echo $(cmd.exe /C "echo | set /p _=%USERPROFILE%") | cat -A
C:\Users\myself
               ^-- all gone!

and now my alias is happy:

export WINHOME="$(wslpath $(cmd.exe /C "echo | set /p _=%USERPROFILE%"))"
1
  • Yes, good point, I remember running into that, then obviously forgot to update my answer - though I removed the \r within WSL, I think I used something like | tr -d '\r' (seeing as \r is not valid within windows paths anyway), but that's just me being more comfortable in Linux
    – dualed
    Feb 15 '19 at 13:01
1
/mnt/c/Users/"$(wslvar USERNAME)"

wslu - a collection of utilities for Windows 10 Linux Subsystem, such as retrieving Windows 10 environment variables or creating your favorite Linux GUI application shortcuts on Windows 10 Desktop.

Requires Windows 10 Creators Update; Some of the feature requires a higher version of Windows 10; Supports WSL2.

3
  • A user directory does not have to be on the C: drive, nor in the Users directory, nor in fact does the user home need to be in a directory named like the username. Drives being mounted in /mnt/ is probably also distribution-specific... wslu seems like a good idea if you need support on older systems, but why didn't you just use wslupath "$(wslvar USERPROFILE)"?
    – dualed
    Oct 20 '20 at 21:09
  • Try to create a file for example: touch wslpath "$(wslvar USERPROFILE)"/test.txt. As a result: touch: cannot touch 'C:\Users\SOME_USERNAME/test.txt': No such file or directory. Or like this: touch /mnt/c/Users/"$(wslvar USERNAME)"/test.conf. It works. Yes /mnt may be changed and user profile may not be on C drive. But a similar solution works for me and may be useful in some cases to others.
    – Victor S.
    Oct 22 '20 at 9:06
  • 1
    It does work with the correct syntax, you have to use a subshell in those cases: touch $(wslpath "$(wslvar USERPROFILE)"/test.txt)
    – dualed
    Oct 24 '20 at 7:04
0

Assuming that you know your Windows userid, you can put this in your .profile: export WINHOME=$(wslpath C:/Users/dualed)

5
  • 1
    I don't want to hardcode the path, otherwise I could simply set the Unix path directly. Also wslpath only works in insider builds right now.
    – dualed
    Nov 24 '17 at 7:19
  • OK. add these two lines to .profile: Nov 25 '17 at 19:43
  • apps=$(echo $PATH | sed 's/:/\n/g' | grep WindowsApps); export WINHOME=${WINHOME%%/AppData*} Nov 25 '17 at 19:54
  • oops: export WINHOME=${apps%%/AppData*} Nov 25 '17 at 20:10
  • The above will fail if there is more than one WindowsApps in $PATH. Best to just create a one-line shell script containing: echo "$PATH" | sed 's/:/\n/g' | grep WindowsApps | sed 's,/AppData.*,, | sort -u Nov 26 '17 at 3:47
-1

Have you tried

env | grep '\\Users\\<your-username>'
?

In Cygwin, I get

HOMEPATH=\Users\<my-username>
USERPROFILE=C:\Users\<my-username>
APPDATA=C:\Users\<my-username>\AppData\Roaming
LOCALAPPDATA=C:\Users\<my-username>\AppData\Local
Of course Cygwin is not the same as WSL, but there might be an easy answer that’s been under your nose all this time.

2
  • Users on WSL are completely independent from Windows users. When setting up a WSL environment you create a completely separate WSL-Only user. A person may choose any name valid in the chosen distribution, so that's not useful in my case as I was looking for a generic solution.
    – dualed
    Feb 14 '19 at 17:28
  • By default Windows variables are not transferred to WSL.
    – pabouk
    Apr 28 '20 at 20:23
-1

in WSL2 all you need is:

echo $PWD

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.