apparix(1)
okay bestie, this is the apparix(1) manual, USER COMMANDS edition ๐ so yes, it's for regular humans too ๐ซถ
๐ NAME ๐
apparix - augmenting cd with bookmarks โจ
๐ฆ SYNOPSIS ๐ฆ
okay so apparix lets you bookmark directories and then jump to them just by typing the mark ๐. By default it acts as a replacement for cd, and you use it the exact same way, including the special behaviour for cd without argument and cd - ๐
. You can also jump straight to subdirectories of a bookmarked directory ๐ง. The contributed bash completion code helps you complete both bookmarks and directories, and you can tweak it to match your own preferences ๐.
ngl this manual page is kinda extra ๐ญ because there are so many examples, explanations of all the bells and whistles, and comparisons with other bookmarking approaches. the core idea is literally just this: type a string you picked and it takes you to the directory tied to it ๐. apparix does very little beyond keeping a list of keys and values. it gets directory names and listings, ties path names (values) to bookmarks (keys), and has some tools for manipulating keys and values ๐. the functions involving apparix (bm, to, and portal) are the user interface ๐. the other functions, als (apparix ls) and ae (apparix edit), are discussed on the main apparix page http://micans.org/apparix ๐
๐ธ GETTING STARTED ๐ธ
first, install apparix ๐ ๏ธ this should be as easy as ./configure --prefix=$HOME/local && make && make install, or maybe a pre-packaged apparix is already available for your system โจ. then grab the to, bm and portal shell handles ๐. these are either aliases or functions depending on your shell. currently csh-style shells and bash are supported. get the ones you need, preferably from http://micans.org/apparix/#shell ๐ฆ. for a more limited set of commands, either visit the FILES section or issue apparix --shell-examples. activate them by pasting them into a shell or adding them to the right resource file, e.g. $HOME/.cshrc or $HOME/.bashrc (do not forget to source the resource file) ๐. the handles to, bm and portal can absolutely be renamed to anything you want ๐. with all that set up, here's a mock-up shell navigation session ๐ฌ
> pwd
/home/eez/cvs/xyz/tfa/faq/zut/bar/foo
> ls
src/ doc/ CVS/ bin/
> bm xkr # bookmark as xkr (funny name though)
> bm # bookmark as foo (trailing component is default)
(later)
> to xkr # cd to /home/eez/cvs/xyz/tfa/faq/zut/bar/foo
(alternatively)
> to xkr src # cd to /home/eez/cvs/xyz/tfa/faq/zut/bar/foo/src
(alternatively)
> to foo # cd to /home/eez/cvs/xyz/tfa/faq/zut/bar/foo
(later)
> ls
aap pyu/ qua tim/ zut/
> pwd
/home/eez/another/branch/deep/down/under
> portal # bookmark as portal, imports tim zut pyu bookmarks
added flock of 3 in portal /home/eez/another/branch/deep/down/under
(later)
> to zut # cd to /home/eez/another/branch/deep/down/under/zut
(later)
> apparix # show all bookmarks
--- portals
e /home/eez/another/branch/deep/down/under
--- expansions
j pyu /home/eez/another/branch/deep/down/under/pyu
j tim /home/eez/another/branch/deep/down/under/tim
j zut /home/eez/another/branch/deep/down/under/zut
--- bookmarks
j xkr /home/eez/cvs/xyz/tfa/faq/zut/bar/foo
j foo /home/eez/cvs/xyz/tfa/faq/zut/bar/foo
in that last example, apparix just shows you every bookmark ๐ the first batch is portals ๐ the second batch is secondary bookmarks expanded from portals ๐ฑ and the third batch is all the regular bookmarks ๐
in the default definitions of to, it falls back to regular cd behaviour if a mark isn't found. it does this by checking whether the mark exists as the name of a directory. you can do that check before bookmark lookup, after it, or not at all ๐คทโโ๏ธ by default the bash completion code takes both bookmarks and directories into account ๐
apparix also allows subdirectory specification of bookmarked locations. combine that with the bash completion code and you get a seriously powerful way to navigate container directories, i.e. directories holding a large number of subdirectories ๐ฅ check out the subdirectory specification section for the details.
๐ Further options ๐
--add-markโ add a jump bookmark--add-portalโ add a portal bookmark-sm <mark>โ squash repeated marks-sd <mark>โ squash repeated destinations-lm <mark>โ list bookmarks with this mark-ld <mark>โ list destinations with mark indirection-favour <list>โ duplicate resolution policy-pick <num>โ immediate duplicate resolution-purge patโ delete bookmarks-purge-mark (pat)โ purge marks, using pat-dโ dump the resource file to STDOUT-lโ list available jumps-u <num>โ remove the last<num>additions--rehashโ re-expand portal bookmarks--buโ create a backup of the resource file-bu <fname>โ create a backup in<fname>--cwdโ usegetcwd(3), notpwd(1)--shell-examplesโ output example macros
It is an absolute prerequisite that -favour is used in the bash completion code, bestie ๐จ Otherwise completion will fail (for a duplicated bookmark) while apparix is waiting for input. Refer to the tab completion description below ๐
โจ subdirectory specification โจ
When you're jumping (apparating ๐ง), you can add an extra subdirectory after the bookmark. Apparix will append that subdirectory to the destination ๐ฆ
This is so useful for projects with directory nodes that match versions. Say you have a structure like this:
/x/y/z/OpusMagnum/v1/
/x/y/z/OpusMagnum/v2/
/x/y/z/OpusMagnum/v3/
Honestly, the easiest move is to bookmark the OpusMagnum directory (say, with the bookmark om). Then you can type to om v2 to jump straight to OpusMagnum/v2 ๐
This is way more flexible and maintainable than making bookmarks om1, om2, and om3. You could add OpusMagnum as a portal, but with generic names like v1 that's not a very extendible approach ๐
Also peep the tab completion section below, because you can tab-complete on subdirectories of the apparix jump directory ๐ซถ
โจ tab completion โจ
The bash tab completion code does two things ๐ First, you can tab-complete on apparix bookmarks themselves, which shows a listing of all available bookmarks (or cycles through them in cyclic mode, depending on your bash settings). Second, once a bookmark has been given, tab completion will list or iterate over all the subdirectories of the directory linked to that bookmark. If you put a string after the bookmark, completion gets limited to directories matching the shell pattern in string. Very useful, ngl โจ
๐จ Be careful to not remove the -favour list option from the bash completion code. It is necessary to resolve duplicate bookmarks.
โจ editing bookmarks โจ
Apparix adds new bookmarks to the very end of the .apparixrc file ๐ Nothing is stopping you from editing the file yourself, and that's actually recommended if you need to get rid of a bookmark and none of -purge, -purge-mark, -sd, or -sm fits your needs. Apparix was never given editor capabilities on purpose. It was an easy design choice, iykyk ๐คท
โจ copying and moving files โจ
It's super straightforward to copy or move files to locations apparix knows about. Examples:
โจ BASH and variants โจ
cp FOO $(apparix zoem)
mv BAR $(apparix zoem doc)
mv BAR $(apparix zoem doc)/test
โจ CSH and variants โจ
cp FOO `apparix zoem`
mv BAR `apparix zoem doc`/test
โจ listing bookmarks โจ
Just typing apparix gives you a list of bookmarks sorted into three categories: portals, expansions, and bookmarks ๐ Use -d to dump the resource file to STDOUT exactly as it is. This is clutch when you want to use -u num to remove the bookmarks or portals you added most recently ๐
Use -l to list all available jumps without their destinations. The jumps are grouped into expansions resulting from portals and regular bookmarks ๐ธ
โจ replacing cd โจ
With the supplied definition(s) of to, apparix will first check whether the mark is the name of a directory accessible from the current directory. A directory is accessible if it would be a valid argument to cd, so it doesn't have to be a subdirectory of where you're standing ๐งญ If the mark isn't an accessible directory, apparix then tries to look it up in the bookmark files. This behaviour can be flipped so the lookup happens first and the current directory gets checked afterwards. Both modes can make to a drop-in replacement for cd โจ Plus, just like cd, to - takes you to the previous directory, and to with no arguments takes you home ๐
The bash completion code acts accordingly and should transparently complete on both marks and directories ๐
โจ OPTIONS โจ
For bookmarking and jumping, the best move is to invoke apparix through the aliases (tcsh variants) or functions (sh/bash) listed in FILES ๐ Apparix also has a few options for pruning, squashing, and rehashing bookmarks, and those are best issued by calling apparix directly ๐งน
If you're hunting for marks or destinations matching a certain pattern, just run apparix without arguments and pipe it through your program of choice ๐
Unary options (the ones without arguments) usually start with two hyphens, except for standardized options like -h. Options that take an argument can be converted to a unary key=value notation, so for example, -purge-mark foo is the same as --purge-mark=foo ๐ง
When you invoke it without arguments, apparix will simply dump its bookmarks.
--add-mark(add jump bookmark) โ This one expects trailing[mark [destination]]argument(s), and both are optional ๐ A single argument is treated as a bookmark name mapped to the current directory. If you give two arguments, the last one is taken as the target directory. If you give none, apparix will enlist the current directory as a target, bookmarked by the trailing component of the directory path.--add-portal(add portal bookmark) โ This enlists a directory as a portal and adds all of its subdirectories as bookmarks ๐ท The bookmark name is simply the name of the subdirectory. By default the current directory is added as a portal, but an optional trailing argument overrides that and gets interpreted as the portal location instead.--try-current-first(try current directory before lookup) โ Super useful in the definition of thetowrapper ๐ Before attempting any lookup of the mark, apparix tests whether the supplied mark exists as a subdirectory in the current directory. If it does, the mark simply expands to itself.--try-current-last(try current directory if lookup fails) โ Also useful in the definition of thetowrapper ๐ซง If the lookup of the mark fails, apparix tests whether the supplied mark exists as a subdirectory in the current directory. If it does, the mark simply expands to itself.--notify-current(notify if current directory is used) โ This one is useful in the definition of thebfwrapper, together with either--try-current-firstor--try-current-last. If the mark is found as a subdirectory in the current directory, apparix notifies you of this fact on the diagnostic stream ๐ฃ-sm <mar>(squash repeated marks) โ apparix squashes bookmarks with mark<mark>๐งฝ This is clutch when a mark points to a versioned project and the project gets updated to a new version in a new directory. By default apparix keeps the last one occurring in the resource file (corresponding with-favour O). This option respects the-favouroption if you give it. Duplicating an already existing mark can be useful when it identifies a project whose underlying directory changes every once in a while (e.g. a project downloaded from external sources that comes with version information). It's not strictly necessary to squash bookmarks, sincetofunctions/macros equipped with the-favouroption will generally resolve duplicate matches anyway ๐-sd <mark>(squash repeated destinations) โ All other bookmarks with the same destination as<mark>get removed ๐๏ธ This is great when a given destination has picked up multiple bookmarks and you decide to settle on a favourite ๐-lm <mark>(list bookmarks with this mark) โ Lists all bookmarks<mark>. Noting that it may point to multiple locations, so don't be surprised if you see a few ๐-ld <mark>(list repeated destinations) โ Lists all bookmarks<mark>(noting that it may point to multiple locations) and additionally lists all other bookmarks that share the destination with any of the first bookmarks. This lets you predict the effect of issuingapparix -sd <mark>๐ฎ-purge pat(delete bookmarks) โ Deletes bookmarks where the destination matchespat๐ All deleted bookmarks are printed to STDOUT, so if you regret deleting a bookmark, it's easy to add it back. Portal specifications are never affected.-purge-mark(pat) โ Deletes bookmarks where the mark matchespat. Portal specifications are never affected ๐งน-d(dump resource file to STDOUT) โ Dumps the resource file to STDOUT ๐-l(list available jumps) โ Lists available jumps paragraph-style ๐ Portal specifications themselves are excluded, and regular jumps and jumps resulting from portal expansions are listed under different headers.-u <num>(remove last <num> additions) โ Removes the last<num>additions. Portal specifications and regular jumps are treated alike ๐๏ธ--rehash(re-expand portal bookmarks) โ apparix will reread the resource file and reexpand portal locations ๐ This is useful if directories have been added, renamed, or removed. Refer to section ENVIRONMENT for the effect that the environment variableAPPARIXEXCLUDEhas on portal expansion.-favour <list>(set duplicate resolution policy) โ These options have a section all to themselves, so refer to duplicate resolution ๐ซถ-pick <num>(immediate duplicate resolution) โ Same deal as-favour, so refer to duplicate resolution ๐--cwd(use getcwd(3), not pwd(1)) โ By default apparix uses the programpwd(1)rather than the system callgetcwd(3). On some systems it was found that the latter results in paths that contain machine-specific mount components ๐ง apparix will usegetcwd(3)when--cwdis used.--shell-examples(output example macros) โ This outputs example macros ๐ They're also listed in the FILES section, though.--bu(create backup of the resource file) โ This creates the backup file in.apparixrc.bu๐พ-bu fname(create backup of the resource file) โ This creates the backup file infname. Use-dor-bu -to dump to STDOUT ๐ค-h(show synopsis) โ Prints the synopsis of all options ๐--apropos(show synopsis) โ Prints the synopsis of all options too ๐ธ
โจ ENVIRONMENT โจ
โจ APPARIXEXCLUDE โจ
This variable sets the exclusion behaviour when portals are expanded with the --rehash option ๐ซ It has the following syntax:
<[:,][<string>]>+
Basically, it's a list of names with each name preceded by a colon or a comma. A colon means <string> triggers exclusion of directory names whose trailing component is identical to <string>. A comma means <string> triggers exclusion of directory names whose trailing component contains <string> as a substring. Check these out:
export APPARIXEXCLUDE=:CVS:lib,tmp # A - example
export APPARIXEXCLUDE=, # B - curiosity
The first one excludes the directory names CVS and lib, plus any directory name having tmp as a substring ๐งน The second one effectively disables portals ๐, since it specifies the empty string, which is a substring of all strings.
APPARIXTAGโ โจ Okay, this one is a total vibe changer. If it's set, its value gets baked into the names of apparix's resource files. Normally they're.apparixrcand.apparixexpand, but whenAPPARIXTAGis set to<tag>they become.<tag>apparixrcand.<tag>apparixexpand. Super handy if you want different sets of bookmarks on different host machines ๐ฅ๏ธ๐APPARIXLOGโ ๐ If this is set, it's treated as the name of a log file. The log keeps track of every newly added bookmark and portal and never deletes anything, using the same format as the.apparixrcfile. Not set? Then nothing gets tracked, bestie ๐ โโ๏ธAPPARIXPURGEโ ๐๏ธ This one changes how apparix dumps purged bookmarks toSTDOUT. By default they come out as command lines that will re-import the bookmarks if you issue them (aka cut and paste 'em โ๏ธ). Set it to1and the purged bookmarks get dumped in the.apparixrcfile format instead.
๐ FILES ๐
Real talk, you should use aliases or functions to make apparix actually useful ๐
Grab them by giving apparix the --shell-examples option, or scroll down a bit. Also peep the fragment that handles argument completion in bash ๐
$HOME/.apparixrcโ This is the main resource file ๐ You usually don't need to touch it by hand. Sometimes it's handy to edit it manually to yank out a bookmark you don't want anymore, so refer to editing bookmarks for that.$HOME/.apparixrc.buโ apparix makes a back-up file whenever it's asked to remove entries from the main file ๐ Check out editing bookmarks for the options that induce removal. You can also demand a backup yourself with either--buor-bu fname.$HOME/.apparixexpandโ This holds the bookmarks that get expanded from portals ๐ธ A portal is just some directory, and the names of all its subdirectories become bookmarks pointing to those subdirectories. This file can be recreated by issuing:
apparix --rehash
$HOME/.bashrc,$HOME/.tcshrc,$HOME/.cshrcโ Add the code you need to the appropriate rc file ๐ The macros and functions below pointcd(1)in the right direction ๐งญ
๐ BASH-style functions ๐
function to () {
if test "$2"; then
cd "$(apparix --try-current-first -favour rOl "$1" "$2" || echo .)"
elif test "$1"; then
if test "$1" == '-'; then
cd -
else
cd "$(apparix --try-current-first -favour rOl "$1" || echo .)"
fi
else
cd $HOME
fi
}
function bm () {
if test "$2"; then
apparix --add-mark "$1" "$2";
elif test "$1"; then
apparix --add-mark "$1";
else
apparix --add-mark;
fi
}
function portal () {
if test "$1"; then
apparix --add-portal "$1";
else
apparix --add-portal;
fi
}
# function to generate list of completions from .apparixrc
function _apparix_aliases ()
{ cur=$2
dir=$3
COMPREPLY=()
nullglobsa=$(shopt -p nullglob)
shopt -s nullglob
if let $(($COMP_CWORD == 1)); then
# now cur=<apparix mark> (completing on this) and dir='to'
# Below will not complete on subdirectories. swap if so desired.
# COMPREPLY=( $( cat $HOME/.apparix{rc,expand} | grep "j,.*$cur.*," | cut -f2 -d, ) )
COMPREPLY=( $( (cat $HOME/.apparix{rc,expand} | grep "\<j," | cut -f2 -d, ; ls -1p | grep '/$' | tr -d /) | grep "\<$cur.*" ) )
else
# now dir=<apparix mark> and cur=<subdirectory-of-mark> (completing on this)
dir=`apparix --try-current-first -favour rOl $dir 2>/dev/null` || return 0
eval_compreply="COMPREPLY=( $(
cd "$dir"
\ls -d $cur* | while read r
do
[[ -d "$r" ]] &&
[[ $r == *$cur* ]] &&
echo \"${r// /\\ }\"
done
) )"
eval $eval_compreply
fi
$nullglobsa
return 0
}
# command to register the above to expand when the 'to' command's args are
# being expanded
complete -F _apparix_aliases to
๐ซง CSH-style aliases ๐ซง
# The outcommented alias does not supplant cd, the other one does.
# alias to 'cd `(apparix -favour rOl \!* || echo -n .)`'
alias to '(test "x-" = "x\!*") && cd - || (test "x" != "x\!*") && cd `(apparix --try-current-first -favour rOl \!* || echo -n .)` || cd'
alias bm 'apparix --add-mark \!*'
alias portal 'apparix --add-portal \!*'
More elaborate setups are possible ๐ง This CSH-style alias:
alias to '(test "x" != "x\!*") && cd `(apparix -favour rOl \!* || echo -n .)` || apparix -l'
...lists all available jumps if invoked without arguments ๐บ๏ธ
๐ง NOTES ๐ง
Okay, so here are some hot takes on other ways people navigate the file system ๐ HISTORY spills the tea on the difference between the venerable cdargs program and apparix ๐ต
CDPATH is only useful when a given directory has subdirectories with distinctive names ๐ It doesn't really scale well once you've got more than a few paths in CDPATH ๐ฌ
Some people use aliases to jump to often visited directories. I was one of them for a period of ten years ๐ The fact is, those aliases are cumbersome to create and remove, and they clutter up the alias namespace. They can clash with executable names when the alias includes the cd part. This sometimes prohibits one from assigning the logical bookmark to a given location, especially when one has a lot of source code locations. They can also clash with directory names when the aliases just expand to the location, which again means that sometimes a location cannot be assigned its logical bookmark. I have found that setting cd jumps aside in their own namespace improves file system navigation by a large factor ๐
It is also possible to create symlinks to often visited files. Again, creation and removal of these are cumbersome ๐ค One could of course create shell functions with a similar interface to apparix or cdargs to handle the symlink lifecycle. On Linux Weekly News, nix suggested putting these symlinks in a single directory and adding that directory to CDPATH. This is quite a neat trick and effectively creates a bookmark navigation system ๐ฆ
Still, there are problems with the above approach. One problem with the symlink approach is that they are a bit awkward to edit. One could make a utility to wrap around the problem, but in the end the directory-with-symlinks would functionally be the same as apparix's .apparixrc resource file, only more of a kludge ๐ Another problem is that symlinks are awkward when traversing the file system. They confuse the notion of parent directory, and cd .. mostly does the unexpected. Sometimes .. has a different meaning to cd than it has to another application, as one will trace back symlinks and the other will not. Finally, a minor objection is that I find it convenient to have bookmarks in a separate namespace from that of cd(1). Jumps are magical, and it's natural to invoke them by a different method. This is in fact how apparix acquired its CDPATH behaviour. I used CDPATH to jump to a few particular source directories with distinct names that lay deeply hidden in some CVS directory. Once I started using apparix, however, I would mistakenly issue to rather than cd to jump to those locations. My brain classified both types of jump in the same category ๐คฆโโ๏ธ
Apparix (and cdargs) have another use besides jumping, namely annotation. Whenever I end up in an esoteric part of the file system and need to make a quick note of the location, I simply bookmark it ๐
On SlashDot, that eternal source of wisdom or alternatively the geek wheel of suffering, Clueless Moron offered the following gems ๐
mk() { eval ${1:-MKPWD}=\"`pwd`\"; }
rt() { eval cd \"\$${1:-MKPWD}\";pwd; }
# type "mk" (as in "mark") and "rt" (as in "return") to mark
# a directory and later go back to it.
# Or give it a name: do "mk foo", and later on "rt foo"
This of course is a per-session mechanism, but it's noteworthy for its simplicity ๐ซถ I am not sure whether csh-style shells could offer an equivalent.
A feature shared by apparix and cdargs is that adding a bookmark immediately takes effect in all shells โก There is no need to source some resource file, as the applications do this every time they are invoked. It is fast, do not worry ๐
๐ BUGS ๐
The resource file parsing code thinks that parentheses are special. Also, records are currently separated by commas.
๐จ Accordingly, apparix will hitch if a path name contains a parenthesis or a comma. Bestie, be careful with those characters in your path names! ๐
๐ AUTHOR ๐
Stijn van Dongen ๐
๐ซถ THANKS ๐ซถ
Stefan Kamphausen wrote cdargs, the inspiration for apparix ๐
Sitaram Chamarty fixed up some of the existing bash code, and added the tab completion part (basing this on similar code in cdargs). He does not guarantee predictable or even pretty results if there are spaces in the directory names you attempt to complete. AUTHOR would like to submit that spaces in path names are evil, and that the completion code seems to work in their evil presence anyway. Just don't put commas in path names ๐ โโ๏ธ
The autotooled build environment was modified from a template written by Joost van Baal ๐ง
Several people suggested enabling apparix to merge accessible directories and marks, but Matias Piipari phrased it the most convincingly ๐
๐ฐ๏ธ HISTORY ๐ฐ๏ธ
Apparix was created to optimize a scenario that cdargs doesn't support very well, namely where the mark (called needle in cdargs) is always known. As additional features, apparix supports CDPATH-style behaviour, derived subdirectory specification, and transparent treatment of bookmarks and directories, all integrated with bash tab completion โจ In other respects apparix is a much simpler application. cdargs offers menu-based navigation of the file system and the bookmark list, which apparix does not ๐
Bestie, that's the whole page, you survived! ๐ Thanks for sticking with it ๐ This version is apparix 1.004 (11-062), last touched 3 Mar 2011 ๐ฆโจ
๐ฆ where this page comes from
- debian bookworm: apparix 11-062-1 ยท GPL-2.0-or-later
- debian trixie: apparix 11-062-3 ยท GPL-2.0-or-later
- ubuntu jammy: apparix 11-062-1 ยท GPL-2.0-or-later
- ubuntu noble: apparix 11-062-1 ยท GPL-2.0-or-later
- ubuntu questing: apparix 11-062-3
- ubuntu resolute: apparix 11-062-4 ยท GPL-2.0-or-later
- ubuntu stonking: apparix 11-062-4 ยท GPL-2.0-or-later
- Copyright (c) 2011 Stijn van Dongen
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms