bash - personalizar - Desafío de código: Acortar ruta de acceso rápido
linux prompt colors (4)
Implementé un acortador de ruta para que se incluya bash en la variable de entorno PS1, lo que acorta el directorio de trabajo en algo más compacto pero aún descriptivo. Tengo curiosidad por saber qué otras ideas pueden existir.
Aquí está el desafío:
Cree una función bash _dir_chomp
que pueda incluirse en PS1 de esta manera (se insertan saltos de línea para facilitar la lectura):
PS1=''/[/033[01;32m/]/u@/h/[/033[01;34m/] $(
_dir_chomp "$(pwd)" 20
)/[/033[01;37m/]$(parse_git_branch)/[/033[01;34m/] /$/[/033[00m/] ''
siendo "20" el parámetro para la longitud máxima como límite suave. Estos son los ejemplos:
-
/usr/portage/media-plugins/banshee-community-extensions/files
convierte en/u/p/m/b/files
-
/home/user1/media/video/music/live-sets
convierte en~/m/v/m/live-sets
(note el carácter ~ como reemplazo de $ HOME) -
/home/user2/media
NO cambia (no se excede el límite de 20 caracteres) -
/home/user1/this-is-a-very-long-path-name-with-more-than-20-chars
convierte en~/this-is-a-very-long-path-name-with-more-than-20-chars
(el último componente permanece sin acortar: límite suave) -
/home/user1/src
convierte en~/src
($ HOME siempre reducido) -
/home/user1/.kde4/share/config/kresources
convierte en~/.k/s/c/kresources
(tenga en cuenta que el punto de prefijo se conserva)
El usuario actual es user1.
Se permite llamar a intérpretes externos como awk
, perl
, ruby
, python
pero no programas C compilados o similares. En otras palabras: los archivos de origen externos no están permitidos, el código debe estar en línea. La versión más corta gana. La longitud del cuerpo de la función bash (y las llamadas funciones sub) cuenta, significa:
_sub_helper() {
# this counts
}
_dir_chomp() {
# these characters count (between { and })
_sub_helper "foobar" # _sub_helper body counts, too
}
Así es como acorté mi indicador de bash con la ruta completa en la barra de título (funciona desde la versión 3.0):
_PS1P=('''' ''..'')
PROMPT_COMMAND=''_PS1L=${#DIRSTACK[0]} _PS1D=${DIRSTACK[0]}''
PS1=''/[/e]2;/h:/w/a/]/h ${_PS1P[$_PS1L>36]}${_PS1D:$_PS1L>36?-34:0} /$ ''
Este método requiere una sobrecarga de CPU muy baja.
Esta fue mi propia solución cuando tuve la idea de este desafío. La inspiración en realidad vino del blog de Jolexa .
Así que aquí está, la implementación ruby en forma legible:
a = ARGV[1].gsub(%r{^#{ENV[''HOME'']}}, "~")
b, a = a, a.gsub(%r{/(/.?[^/.])[^/]+(/.*)}, ''//1/2'') while
(a.length > ARGV[2].to_i) && (b != a)
print a
Y la implementación real de una línea dentro de la función bash:
_dir_chomp() {
ruby -e''a="''$1''".gsub(%r{^''$HOME''},"~");b,a=a,a.gsub(%r{/(/.?[^/.])[^/]+(/.*)},"///1//2")while(a.length>''$2'')&&(b!=a);print a''
}
Este es 20 o más caracteres más corto que mi otra respuesta:
_dir_chomp () {
local p=${1/#$HOME//~} b s
s=${#p}
while [[ $p != "${p////}" ]]&&(($s>$2))
do
p=${p#/}
[[ $p =~ /.?. ]]
b=$b/${BASH_REMATCH[0]}
p=${p#*/}
((s=${#b}+${#p}))
done
echo ${b///~//~}${b+/}$p
}
Pure Bash:
_dir_chomp () {
local IFS=/ c=1 n d
local p=(${1/#$HOME//~}) r=${p[*]}
local s=${#r}
while ((s>$2&&c<${#p[*]}-1))
do
d=${p[c]}
n=1;[[ $d = .* ]]&&n=2
((s-=${#d}-n))
p[c++]=${d:0:n}
done
echo "${p[*]}"
}
Para propósitos de prueba, asumo que la pregunta significa que el usuario actual es "usuario1".
Nota: Bash 4 tiene una variable PROMPT_DIRTRIM
que acorta el /w
escape en PS1
al retener el número de subdirectorios según su valor y al reemplazar el resto con ...
/$ PROMPT_DIRTRIM=2
/$ echo $PS1
/w/$
/$ pwd
/
/$ cd /usr/share/doc/bash
.../doc/bash$