27

pwd gives me

/data/users/me/some/random/folder

Is there an easy way of obtaining

~/some/random/folder

from pwd?

  • Is piping through sed an option? – Matthew D. Scholefield Jun 3 '15 at 6:28
  • 7
    If you're going to do this, I'd strongly recommend naming the resulting command something other than pwd. Otherwise, you'll break scripts that expect to use its output in contexts that don't perform tilde expansion. – Charles Duffy Jun 3 '15 at 21:48
24

If your're using bash, then the dirs builtin has the desired behavior:

dirs +0
~/some/random/folder

(Note +0, not -0.)

With zsh:

dirs
~/some/random/folder

To be exactly, we first need to clear the directory stack, else dirs would print all contents:

dirs -c; dirs

Or with zsh's print builtin:

print -rD $PWD

or

print -P %~

(that one turns prompt expansion on. %~ in $PS1 expands to the current directory with $HOME replaced with ~ but also handles other named directories like the home directory of other users or named directories that you define yourself).

  • I switch all the time between bash and zsh. Unfortunately this solution forces me to remember the difference between the shells and also to remember (to check) where I am currently. The answer by @Bichoy is shell-agnostic for these two. – avp Sep 28 '18 at 13:39
17

You can use Bash variable substring replacement feature:

$ pwd
/home/vagrant/foo/bar
$ echo ${PWD/#$HOME/'~'}
~/foo/bar
  • 2
    This also works in ksh and zsh. – mr.spuratic Jun 3 '15 at 8:59
  • 1
    While I have upvoted this answer because its the easiest way, there's a small caveat here: inside /tmp/home/username, this will return /tmp~. I cannot find a way to insert a caret sign before $HOME to fix this. If you need your solution to be perfect, don't use this... – 0fnt Jun 3 '15 at 9:47
  • 1
    @user18151, than you for pointing this out. I replaced my answer to ${string/#substring/replacement} version to prevent this behaviour. – Nykakin Jun 3 '15 at 9:54
  • 1
    @mr.spuratic it's only correct (except for the usage of echo) in zsh. In other shells, $HOME would be treated as a pattern and the whole thing subject to split+glob. – Stéphane Chazelas Jun 3 '15 at 11:07
  • Escaping the tilde ('~') did the trick. Note that \~ also works. This is convenient when already in '-context: e.g., PROMPT_COMMAND='printf "\033]0;%s@%s:%s\007" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/\~}"' – Atafar Feb 8 at 11:38
7

Using sed:

pwd | sed "s|^$HOME|~|"

The idea is to use any character that is less likely to appear in a home directory path as the delimiter in sed regex. In the example above I am using |.

The good thing about this technique is that it is actually shell-independent.

You can also alias pwd to /bin/pwd | sed "s|$HOME|~|" to get this behavior in other scripts that might be using pwd.

  • 2
    You need to include the ^ anchor in your regex. Otherwise, it is possible (however unlikely) for this to replace a segment in the middle of the path. – Sildoreth Jun 3 '15 at 13:33
  • Actually the regex should look as follows "s|^/home/user\(/.*\)\?$|~\1|". Otherwise it matches other users' paths if their names are like user1, user2, user3 and you match just user – avp Sep 28 '18 at 13:24
3
tilde=\~${PWD#~}

I think that's what you want?

What's neat about the tilde is when it is expanded as a pattern it doesn't need quoting. Using $HOME in that same way without quotes would render unpredictable results because any of its constituent characters could be pattern characters, and so it might not always render the result expected.

But the tilde expansion is spec'd to always occur as if it were the result of a quoted expansion, and so its results are predictable. This seems to hold true in practically every shell I've tested for both case patterns and parameter patterns with the notable exceptions of both ksh93 and mksh for whatever reasons - neither of which seems to honor the quoted aspect of the tilde in that capacity.

Another neat thing about this is that you can redefine $HOME to handle any directory at all in the same fashion. For example:

cd ~
HOME=/some/prefix/I/would/like/to/trim 
#or, perhaps more usefully, some scripted means of arriving at same
tilde=\~${OLDPWD#~}
HOME=$PWD

Here's another example:

set 1 2 3 4 5 \~
cd ~; cd -; HOME= IFS=/
for d do shift
      HOME=${*#~/}/$d
      set ~ "$d" $HOME
done; cd -; HOME=$PWD
printf %s\\n "$@"
5/4/3/2/1/2/3/4/5/~/1/2/3/4/5/~
~
5
4
3
2
1
2
3
4
5
~
1
2
3
4
5
~
  • 1
    That's a really interesting approach. But it assumes that $PWD is under $HOME. You could use the same idea combined with pattern substitution to make it more general. How's ${PWD/#~/\~}? – Mikel Jun 3 '15 at 16:52
  • 1
    Actually Nykakin's answer is basically that. – Mikel Jun 3 '15 at 16:53
0

You can try replacing the unwanted part with sed:

pwd | sed 's,^/data/users/me,~,'

or even better:

pwd | sed "s,^$HOME,~,"
  • 1
    You need to use the ^ anchor to ensure that only matches at the beginning of the directory path are replaced. Also, you don't need to use g because the command should be replacing 1 occurrence at most. – Sildoreth Jun 3 '15 at 13:41
  • Thank you. I am still learning this things and you comment is really helpfull. – user1403360 Jun 4 '15 at 6:54
  • Problematic if my home directory is /home/alice and my current directory is /home/aliceinchains. But if the only time I ever want to use the feature is when I know I'm my home directory or one of its subdirectories, then it should work. – Mihai Danila Jul 22 '17 at 21:53

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.