Here's a bash-only solution that you might like. This shortens each part of the path down to the shortest prefix that can still be tab-completed, and uses * instead of .. as the filler.
#!/bin/bash
begin="" # The unshortened beginning of the path.
shortbegin="" # The shortened beginning of the path.
current="" # The section of the path we're currently working on.
end="${2:-$(pwd)}/" # The unmodified rest of the path.
end="${end#/}" # Strip the first /
shortenedpath="$end" # The whole path, to check the length.
maxlength="${1:-0}"
shopt -q nullglob && NGV="-s" || NGV="-u" # Store the value for later.
shopt -s nullglob # Without this, anything that doesn't exist in the filesystem turns into */*/*/...
while [[ "$end" ]] && (( ${#shortenedpath} > maxlength ))
do
current="${end%%/*}" # everything before the first /
end="${end#*/}" # everything after the first /
shortcur="$current"
shortcurstar="$current" # No star if we don't shorten it.
for ((i=${#current}-2; i>=0; i--))
do
subcurrent="${current:0:i}"
matching=("$begin/$subcurrent"*) # Array of all files that start with $subcurrent.
(( ${#matching[*]} != 1 )) && break # Stop shortening if more than one file matches.
shortcur="$subcurrent"
shortcurstar="$subcurrent*"
done
begin="$begin/$current"
shortbegin="$shortbegin/$shortcurstar"
shortenedpath="$shortbegin/$end"
done
shortenedpath="${shortenedpath%/}" # strip trailing /
shortenedpath="${shortenedpath#/}" # strip leading /
echo "/$shortenedpath" # Make sure it starts with /
shopt "$NGV" nullglob # Reset nullglob in case this is being used as a function.
Give it the length as the first argument, and the path as the optional second argument. If no second argument is given, it uses the current working directory.
This will try to shorten to under the length given. If that's not possible, it just gives the shortest path it can give.
Algorithmically speaking, this is probably horrible, but it ends up being pretty fast. (The key to quick shell scripts is avoiding subshells and external commands, especially in inner loops.)
By design, it only shortens by 2 or more characters ('hom*' is just as many characters as 'home').
It's not perfect. There are some situations where it won't shorten as much as is possible, like if there are several files whose filenames share a prefix (If foobar1 and foobar2 exist, foobar3 won't be shortened.)
like/shortened
. I use ZSH, though, so I don't know how you'd do it in bash. – Hippocrenepwd | sed -e "s|.*/\(.*/.*\)|\1|"
– Brightwork