2

I’ve been using Git Bash on Windows, and recently, I had the chance to try Codespace. I loved how the Codespace terminal setup was very clean and simple.

When you open the terminal, there is no path prefix, i.e. when working in the main directory:
$ write_here

and as you move into the subdirectories, it writes the path prefix starting from the first subdirectory after the main one
new/ $ write_here
new/new2/ $ write_here

Basically, all it does is strips away the path prefix of main directory from the full path prefix of any directory

I wanted to replicate this on my main setup, but couldn't find a clean way of scripting this.

What i've tried so far

I tried to customize the prompt by modifying the .bashrc file. For example, I used these two scripts:
(PS: my main directory is /e/VScode)

PS1='${PWD#/e/VScode/} $ ' <br/>
PS1='${PWD//\/e\/VScode\//}/ $ '

Both of these did half the job. They show the reduced path of the subdirectories,
(for example new/new2/ $ write_from_here)
but when it comes to the main directory, it still showed /e/VScode/ $ write_here.

I’m still relatively new to the community, so I’ll admit that I’m not very familiar with all the scripting conventions and techniques yet. But I tried a workaround by introducing separate case for the main directory:

PS1='$(if [ "$PWD" = "/e/VScode" ] 
then 
  echo "$ "; 
else 
  echo "${PWD#/e/VScode/}/ $ "; 
fi)'

And of course, the results are exactly how I wanted them to be.

But:

Even though I can proceed with the workaround, I'm still curious about the ideal, clean, one-cased script line to achieve this result. And why the initial script lines did not work for that one case?

0

3 Answers 3

2

You could use the extglob option:

PS1='$( shopt -s extglob; echo "${PWD##/e/VScode?(/)} $ " )'
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you. It's almost perfect, except that it doesn't return / after the basename (& that's, in fact, a more clean customization), but again, it's still not a solution to replicate the "exact" environment. Now I realize that it's not possible (with the options that I know of) to write a clean script without introducing another variable (say var) that is exactly like PWD but ends with a /. Then removing /e/VScode/ (with a / at the end) will no longer be the problem anymore (that it was in the special case when the dir is /e/VScode, as Mark mentioned in the above answer).
1

OP has stated (in comments) that they wish to duplicate exactly the command prompt under codespace so my original idea (see 2nd half of this answer) is not sufficient.

While it may be possible to shoehorn the conditional logic into a single parameter substitution I'd expect it be a bit ugly and hard to understand.

In this situation I'd opt for something similar to OP's if/then/else/fi workaround ... (relatively) simple to understand and it addresses the desired requirement.

A couple variations on OP's current if/then/else/fi workaround:

######
# define PS1 as output from the if/then/else conditional

PS1='$( [[ "$PWD" = "/e/VScode" ]] && echo "$ " || echo "${PWD#/e/VScode/}/ $ " )'

######
# conditionally define PS1 based on current PWD

PROMPT_COMMAND='[[ "$PWD" = "/e/VScode" ]] && PS1="$ " || PS1="${PWD#/e/VScode/}/ $ "'

With either of these implementations we see:

$ cd sub/dir                      # sitting in /e/VScode
sub/dir/ $ cd /opt                # sitting in /e/VScode/sub/dir
/opt/ $ cd                        # sitting in /opt
$                                 # sitting in /e/VScode

Original answer:

In my environment PWD does not end in a forward slash, eg:

$ cd
$ typeset -p PWD
/home/username

Your parameter substitution is looking for that trailing forward slash on your main directory:

${PWD#/e/VScode/}
               ^

When you're in the main directory the lack of the trailing forward slash (in PWD) means the parameter substitution does not occur. When you're in a subdirectory that trailing forward slash is available and the parameter substitution occurs. In other words:

When PWD is:             ${PWD#/e/VScode/} results in:
==================       =============================
/e/VScode                /e/VScode
/e/VScode/sub            sub
/e/VScode/sub/dir        sub/dir

NOTE: because PWD does not end in a trailing forward slash you will need to add a literal trailing slash (if that's what you want) in the PS1 definition

While there may be a way to conditionally test for the optional trailing forward slash in a parameter substitution, I'm wondering if you might be open to a slight change.

Instead of removing /e/VScode/ would it be ok to replace it with, say, a tilda (~). One idea using a different flavor of parameter substitution (${PWD/old/new}) while insuring we escape literal forward slashes and the tilda:

$ PS1='${PWD/\/e\/VScode/\~} $ ' ; cd
~ $ cd sub                                    # sitting in /e/VScode    
~/sub $ cd dir                                # sitting in /e/VScode/sub
~/sub/dir $ cd /opt                           # sitting in /e/VScode/sub/dir  
/opt $ cd                                     # sitting in /opt
~ $                                           # back to /e/VScode

Adding the trailing forward slash to PS1:

$ PS1='${PWD/\/e\/VScode/\~}/ $ ' ; cd
~/ $ cd sub
~/sub/ $ cd dir
~/sub/dir/ $ cd /opt
/opt/ $ cd
~/ $ 

2 Comments

PWD doesn't end in a "/" for me either. And now I get why my initial try didn't work. But is it possible to define another variable that adds an extra "/" at the end of the PWD, & then use that variable to replace PWD in the main line. Because that would solve the whole problem imo. For eg. if we define that variable asvar and use it in PS1='${var//\/e\/VScode\//} $ '. But when I tried to define var as var="${PWD}/", & substituted var in the main line, it didn't recognize var at all & gave the prompt as if neither of the variable are there. I wonder if there's any syntax in it?
@Nishant I don't see an 'easy' way to do what you want without some sort of conditional logic; your current if/then/else/fi workaround is easy to understand and provides the desired result; I've updated my answer with a couple variations on your current workaround
0

Since you probably want to set PS1 in your profile, you can set extended globbing at the same time.

shopt -s extglob
PS1='${PWD/#\/c\/Users?(\/)/~\/} $ '

I leave extended globbing on all the time, but be aware of the effect that might have on anything else.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.