Trimming PS1's working directory path - linux

Is there a way to get my ubuntu command prompt to be something like:
user#host:home$
but still have the behavior of:
user#host:home$ cd projects
user#host:home/projects$
Right now, my working directory path before the home directory is cluttered with stuff from my school's servers (e.g. user#host:/blah/blah/blah/home$ ). Is there a way I can still append the directory path to the prompt as I navigate around, but just trim the beginning stuff off?

You can create a function and place it in your rc file (perhaps ~/.bashrc) like this:
function simplify_dir {
local PREFIX
if [[ $PWD == "$HOME"* ]]; then
PREFIX=${HOME%/}
PREFIX=${PREFIX%/*}
echo "${PWD##"$PREFIX/"}"
else
echo "$PWD"
fi
}
Also add this command to enable expansion in prompt:
shopt -s promptvars
Then set your PS1 prompt to something like this:
PS1='\u#\h:$(simplify_dir)\$ '

Try out this one:
PS1="[\u#\h:\w ] $ "
Case matters:
\w : the current working directory, with $HOME abbreviated with a tilde
\W : the basename of the current working directory, with $HOME abbreviated with a tilde

Related

Relative path to the home directory (linux)

When I use pwd it returns:
/home/ahmad/multifit-pretrain-lm/multifit/datasets
I look for a command so that I get the path relative to the home directory
multifit-pretrain-lm/multifit/datasets
I look for a command so that I get the path relative to the home directory
You can use bash parameter substitution here:
echo "${PWD#"$HOME"/}"
$PWD shell variable returns same value as the command pwd
${PWD#"$HOME"/} strips "$HOME"/ at the start from $PWD
Variable substitution is a good solution but since you asked for a command, here is one:
realpath --relative-base="$HOME" .

on the "local" toolchain in linux

long time lurker first time poster.
I've looked everywhere and I'm sure it's easily found but I couldn't properly word the search.
I working on some coding exercises from a textbook and I've got all my work in directories with the following hierarchy:
r00t
/ \
tools code
\
chapts
In the tools directory are a couple scripts to make my life easier. What I want, and the reason I'm posting, is to be able to call the scripts in r00t/tools wherever I am, as long as I'm inside r00t. I know I could just add them to the global PATH but that seems lazy and I don't want my PATH to balloon any more (is this even sensible?).
So, can I add scripts or programs to the "local PATH" inside the dir somehow?
Take a look over here towards the ondir (link) program letting you execute scripts upon entering or leaving directories.
With that you could dynamically change your path variable. I must however admit to never have used the program nor to be informed about its development status.
Alternatively you could replace your cd command with a script checking pwd versus your r00t directory and updating $PATH based on the outcome. of course your cd will be slowed down but probably not even noticeably.
an example:
#!/bin/bash
#alternative cd
cd $*
#check for r00t directory
if [ "$( pwd | grep -o 'r00t')" == "r00t" ] ; then
#check path variable:
if [ "$(echo $PATH | grep -o 'r00t')" != "r00t" ] ; then
export PATH=$PATH:/DIR/r00t/bin
fi
else
#remove r00t from PATH when not in r00t
if [ "$(echo $PATH | grep -o 'r00t')" == "r00t" ] ; then
export PATH=$( echo $PATH | sed 's~:/DIR/r00t/bin~~' )
fi
fi
note that now you'll have to intoduce the alias as follows:
alias cd='. ./path/to/script/alternative_cd.sh'
as the exported PATH needs to be sourced in order to work for your current shell (if using bash alternative_cd.sh, you'd only get the new PATH for the subshell the script is run in)
I tested it and it seemed to be working. Have fun.
The usual way to handle this is to put an rc file in the root directory of each of your project directory trees. In this case, r00t. Call the file r00trc or make your own naming convention.
The rc file should include an identifying change to the command line prompt in order to remind you constantly what environment the shell is using, and a re-assignment of the PATH variable to suite the needs of the project, and any other project-specific environment variables, aliases or color setting that you need.
From your default login environment, spawn a sub-shell by running 'bash' either before or after or without changing the current working directory to r00t and then source the r00trc file. This provides you with a Bash shell with the project environment and an identifying prompt. Use exit to exit the sub-shell and return to your default environment.
Avoid the temptation to collect your project rc files in your home directory or anywhere other than the root of the project directories so that they do not get lost when you tar up a project and archive it or send it to a colleague.

cygwin tilde expansion not working in interactive shell

For some reason tilde expansion in Cygwin is not working for me at the prompt:
$ ls ~
ls: cannot access : No such file or directory
$ ls ~/bin
(lists /bin not $HOME/bin)
$ echo $HOME
/home/myusername
$ echo ~
$
In the last case there (echo ~) there is no output (other than a couple of blank lines.)
I have set expand-tilde on set in my $HOME/.inputrc file. Is there something else I need configured?
This is a recurring problem with Cygwin that, I believe, was tied to some upgrade bug a while ago and never resolved.
In any case, the solution is simple: open /etc/passwd in your favourite editor, and on the line with your username, between the fifth and sixth colons (the last and second-to-last), write in the correct path to your home directory, ie /home/myusername.
The relevant line in my /etc/passwd looks something like the below:
meand:unused:12345:54321:PCNAME\meand,S-1-5-21-4567891230-654987321-312456978-58252:/home/meand:/bin/screen

Dynamically computed Bash variable

I have several similarly structured directory trees.
something like:
~/
Tree1/
src/
bin/
Tree2/
src/
bin/
When I somewhere below Tree1/src I want to work with Tree1/bin. When I somewhere below Tree2/src I want to work with Tree2/bin.
Is there a way to define a shell variable whose value depends on my current working directory?
PWD is a variable already set to your current directory by bash, ksh and other shells.
cwd=$(pwd) should do the trick. It assigns the output of print working directory (pwd) to a variable.
To replace ~Tree1/src/dir1/dir2 with ~Tree1/bin you could do
bindir=$(pwd | sed 's/src.*/bin/')
See also Command Substitution
As jlliagre stated, bash (as many other modern shells) stores the current working directory in $PWD; if it is Tree1/src/some/other/directory, then you can extract "Tree1/bin" from it by just using "parameter expansion":
$ echo $PWD
Tree1/src/some/other/directory
$ echo ${PWD%%src*}bin
Tree1/bin
Generally $PWD variable (Present Working Directory) contains the path to the current directory. If this variable is not defined, you can use the pwd command that will return the current path.
Two other definitions of "current" include the directory you were in when the script was started (which is the value of start_dir="$PWD" at the start of the file, no matter where the script is) and the directory of the script itself - script_dir="$(dirname -- "$(readlink -f -- "$0")")".

How can a bash script know the directory it is installed in when it is sourced with . operator?

What I'd like to do is to include settings from a file into my current interactive bash shell like this:
$ . /path/to/some/dir/.settings
The problem is that the .settings script also needs to use the "." operator to include other files like this:
. .extra_settings
How do I reference the relative path for .extra_settings in the .settings file? These two files are always stored in the same directory, but the path to this directory will be different depending on where these files were installed.
The operator always knows the /path/to/some/dir/ as shown above. How can the .settings file know the directory where it is installed? I would rather not have an install process that records the name of the installed directory.
I believe $(dirname "$BASH_SOURCE") will do what you want, as long as the file you are sourcing is not a symlink.
If the file you are sourcing may be a symlink, you can do something like the following to get the true directory:
PRG="$BASH_SOURCE"
progname=`basename "$BASH_SOURCE"`
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
dir=$(dirname "$PRG")
Here is what might be an elegant solution:
script_path="${BASH_SOURCE[0]}"
script_dir="$(cd "$(dirname "${script_path}")" && pwd)"
This will not, however, work when sourcing links. In that case, one might do
script_path="$(readlink -f "$(readlink "${BASH_SOURCE[0]}")")"
script_dir="$(cd "$(dirname "${script_path}")" && pwd)"
Things to note:
arrays like ${array[x]} are not POSIX compliant - but then, the BASH_SOURCE array is only available in Bash, anyway
on macOS, the native BSD readlink does not support -f, so you might have to install GNU readlink using e.g. brew by brew install coreutils and replace readlink by greadlink
depending on your use case, you might want to use the -e or -m switches instead of -f plus possibly -n; see readlink man page for details
A different take on the problem - if you're using "." in order to set environment variables, another standard way to do this is to have your script echo variable setting commands, e.g.:
# settings.sh
echo export CLASSPATH=${CLASSPATH}:/foo/bar
then eval the output:
eval $(/path/to/settings.sh)
That's how packages like modules work. This way also makes it easy to support shells derived from sh (X=...; export X) and csh (setenv X ...)
We found $(dirname "$(realpath "$0")") to be the most reliable with both sh and bash. As team mates used them interchangeably, we ran into problems with $BASH_SOURCE which is not supported by sh.
Instead, we now rely on dirname, which can also be stacked to get parent, or grandparent folders.
The following example returns the parent dir of the folder that contains the .sh file:
parent_path=$(dirname "$(dirname "$(realpath "$0")")")
echo $parent_path
I tried messing with variants of $(dirname $0) but it fails when the .settings file is included with ".". If I were executing the .settings file instead of including it, this solution would work. Instead, the $(dirname $0) always returns ".", meaning current directory. This fails when doing something like this:
$ cd /
$ . /some/path/.settings
This sort of works. It works in the sense that you can use the $(dirname $0) syntax within the .settings file to determine its home since you are executing this script in a new shell. However, it adds an extra layer of convolution where you need to change lines such as:
export MYDATE=$(date)
to
echo "export MYDATE=\$(date)"
Maybe this is the only way?

Resources