We want:
To use it, put the code below in your
$HOME/.bashrc or /etc/bash.bashrc and start a
new bash to use it.
Bold blue text in the examples is user input.
cd command should not be necessary. With
shopt -s autocd
you can omit the cd command to change a directory.
cd - you can go back to your last directory, but there
is no command to go to the last but one or even older directories.
With
declare -a DIRS
savedir() {
local i
for ((i=1;i<=9;i++)); do
test "$1" = "${DIRS[$i]}" && return
done
for ((i=9;i>1;i--)); do
DIRS[$i]="${DIRS[((i-1))]}"
done
DIRS[1]="$1"
}
showdirs() {
local i=1
while [ "${DIRS[$i]}" ]; do
echo "$i: ${DIRS[$i]}"
((i++))
done
}
gotodir() {
local d
showdirs
printf "goto: "
read -n 1 d
echo
cd "${DIRS[$d]}"
}
PROMPT_COMMAND=prompt_command
prompt_command() { savedir "$OLDPWD"; }
alias cdh=gotodir
you have a directory history, which you can access with the
cdh command. Example:
framstag@fex:~: cd /sw/share/fstools-0.0/bin framstag@fex:/sw/share/fstools-0.0/bin: cd /tmp framstag@fex:/tmp: cd /etc/X11 framstag@fex:/etc/X11: cd framstag@fex:~: cdh 1: /etc/X11 2: /tmp 3: /sw/share/fstools-0.0/bin 4: /home/framstag goto: 3 framstag@fex:/sw/share/fstools-0.0/bin:
$PATH
and run source $(cdbm -S)
Afterwards you can use cdb to save, change, remove or go to a
directory with just one key.
Example:
root@fex:~# cdb [+] add bookmark [-] del bookmark [>] move bookmark [?] toggle help [a] /etc/amavis/conf.d [p] /etc/postfix [u] /export/backup/U10 [v] /var/lib/amavis/virusmails [w] /export/home/httpd/virtual/flupp.belwue.de [v] root@fex:/var/lib/amavis/virusmails#
See also mklink
cdw() {
if [ -z "$1" ]; then
echo >&2 "usage: cdw program_or_file"
elif [[ "$1" =~ / ]]; then
cd $(dirname "$1")
else
ap=$(type -P "$1")
if [ "$ap" ]; then
cdw $(readlink -f "$ap")
else
echo >&2 "$1 not found"
fi
fi
}
you can call cdw PROGRAM to change to the directory where
PROGRAM is, for example:
framstag@fex:~: cdw dsmc framstag@fex:/opt/tivoli/tsm/bin: ll dsmc -rwxr-xr-x root root 202 2015-08-14 15:52:27 dsmc framstag@fex:/opt/tivoli/tsm/bin: cdw fexsend framstag@fex:/sw/share/fstools-0.0/bin: ll fexsend -rwxr-xr-x framstag root 95,081 2016-08-29 09:06:03 fexsend
You can also call cdw with any path (e.g. by mouse copy&paste)
and it will change to the pertaining directory, example:
cdw /boot/grub/grub.cfg
cdu() {
declare -a x
declare -A D
local n=$1
local i=0
local dir=$(realpath .)
x=({0..9} {a..z})
if [[ $1 =~ [a-z] ]]; then
echo "cdu: cd upwards"
echo "usage: cdu [NUMBER_OF_PARENT_DIRECTORIES]"
return
fi
while [[ $dir =~ /.+/ ]]; do
((i++))
dir=$(dirname "$dir")
D[${x[i]}]="$dir"
done
if [ -z "$n" ]; then
for (( n=1; n<=i; n++ )); do
echo "[${x[n]}] ${D[${x[n]}]}"
done
printf "[ ]\r["
read -n 1 n
test -z "$n" && return
echo
fi
if [ "${D[$n]}" ]; then
cd "${D[$n]}"
else
echo >&2 "cdu: no such directory"
fi
}
you can go up any number of directories, for example:
framstag@fex:/sw/share/jedlib-0.99-20_116/lib: cdu [1] /nfs/rusnas/sw/share/jedlib-0.99-20_116 [2] /nfs/rusnas/sw/share [3] /nfs/rusnas/sw [4] /nfs/rusnas [5] /nfs [4] framstag@fex:/nfs/rusnas:
cdd() {
local i=0
local n=1
local find='find . -type d'
local dir dot
local m nn nf ii
declare -a D
[ "$1" = '.' -o "$1" = ':.' ] && dot=true
[ "$1" = ':' -o "$1" = ':.' ] && find="$find -maxdepth 1"
[ "$1" = '.' -o "$1" = ':' -o "$1" = ':.' ] && shift
if [[ $1 =~ ^- ]]; then
echo "cdd: cd downwards (subdir)"
echo "usage: cdd [SUBSTRING]"
return
fi
m=$1
while read dir; do
[ "$dir" = . ] && continue
[ -z "$dot" ] && [[ "/$dir" =~ /\. ]] && continue
for i in $CD_IGNORE; do
[ "$dir" = "$i" ] && continue 2
done
D[n]=$dir
((n++))
done < <(
$find 2>/dev/null|
sed 's/..//'|
fgrep -i "$m"|
while read d; do
test -x "$d" -a -r "$d" && echo "$d"
done|
LC_ALL=C sort -f
)
nn="${#D[@]}"
nf="${#nn}"
if [ $nn = 0 ]; then
return
elif [ $nn = 1 ]; then
i=1
else
for (( i=1; i<=nn; i++ )); do
printf "[%0${nf}d] %s\n" $i "${D[i]}"
done
while :; do
i=
printf "\r[%${nf}s] \r[" ''
while (( "${#i}" < $nf )); do
read -n 1 ii
test -z "$ii" && return
[[ $ii =~ ^[0-9]$ ]] || continue 2
i=$i$ii
done
i="$((10#$i))" # remove leading 0s
test $i = 0 -o -n "${D[i]}" && break
done
echo
fi
test -n "${D[i]}" && cd "${D[i]}"
}
you can go downwards to any subdirectory matching substring, for example:
root@fex:/sw/share# cdd bin [1] s3cmd-2.0.2/bin [2] s3cmd-2.0.2/bin/S3 [3] aggis-1.0/bin [4] linuxtools-0.0/bin [5] linuxtools-0.0/sbin [6] fstools-0.0/bin [7] fstools-0.0/sbin [5] root@fex:/sw/share/linuxtools-0.0/sbin#
newdir() { mkdir -p "$1" && cd "$1"; }
you can call newdir schwupp/di/wupp which creates this
directory and let you enter it, with just one command.
pathuniq() {
if [ -n "$1" ]; then
perl -le 'print join(":",(grep !$_{$_}++,split(":",shift)))' "$1"
else
PATH=$(pathuniq $PATH:)
fi
}
you can call pathuniq which removes double elements from the
PATH environment variable. Example:
framstag@fex:~: echo $PATH /home/framstag/bin:/usr/local/bin:/bin:/sbin:/usr/bin:/bin:/usr/sbin:/bin:/home/framstag/bin framstag@fex:~: pathuniq framstag@fex:~: echo $PATH /home/framstag/bin:/usr/local/bin:/bin:/sbin:/usr/bin:/usr/sbin
You can also call pathuniq with:any:other:argument:any
export BASHCMDLINE= bind -x '"\e$":BASHCMDLINE="$READLINE_LINE"' bind '"\e;":accept-line' bind '"\r":"\e$\e;"'This sets the environment variable
BASHCMDLINE which contains
the original command line before shell expansion.BASHCMDLINE from any programm to query
the original invoke command. In contrast, the classic ARGV variable is the
invoke command after shell expansion!
Example:
framstag@fex:/tmp: cat showargv echo "BASHCMDLINE = [ $BASHCMDLINE ]" echo "ARGV = [ $* ]" framstag@fex:/tmp: bash showargv $PWD * BASHCMDLINE = [ bash showargv $PWD * ] ARGV = [ /tmp framstag root showargv zz ]
search() {
local status=1
if [ -z "$1" ]; then
echo "usage: search substring"
return 2
fi
alias | grep "$1[^ ]*=" && status=0
declare -F | awk '$3 !~ /^_/ {print $3"()"}' | fgrep "$1" && status=0
for d in $(sed 's/:/ /g' <<<$PATH); do
for f in $d/*"$1"*; do
if [ -x "$f" -a -f "$f" ]; then
echo "$f"
status=0
fi
done
done
return $status
}
you can search for commands (alias, functions, programs) by substring.
Example:
framstag@fex: search dir alias copydir='cp -av --parents' newdir() savedir() showdirs() /bin/dir /bin/mkdir /bin/rmdir /usr/bin/dircolors /usr/bin/dirname
For the cd tools you have to extract cdbm in your $PATH
(eg /usr/local/bin or $HOME/bin)
With source $(cdbm -S) you will get:
framstag@fex: cdbm -h
cdb [BOOKMARK] : cd bookmarks
cdh : cd history
cdl [LINK] : cd link (see mklink)
cdu [NUMBER] : cd upwards
cdd [SUBSTRING] : cd downwards (no .directories)
cdd. [SUBSTRING]: cd downwards (with .directories)
cds [SUBSTRING] : cd subdirectory (no .directories)
cds. [SUBSTRING]: cd subdirectory (with .directories)
cda : cd absolute path
cdw /PATH/FILE : cd /PATH
cdw PROGRAM : cd where PROGRAM is in $PATH
cdx PROGRAM : cd where PROGRAM is in $PATH and list it
cde PROGRAM : cd where PROGRAM is in $PATH and edit it
.. : cd one directory up
... : cd two directories up
.. NUMBER : cd NUMBER directories up (".. 2" == "...")
- : cd previous directory
and also mklinkAuthor: Ulli Horlacher