From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 17691 invoked from network); 6 Mar 2000 21:15:16 -0000 Received: from sunsite.auc.dk (130.225.51.30) by ns1.primenet.com.au with SMTP; 6 Mar 2000 21:15:16 -0000 Received: (qmail 15398 invoked by alias); 6 Mar 2000 21:14:57 -0000 Mailing-List: contact zsh-users-help@sunsite.auc.dk; run by ezmlm Precedence: bulk X-No-Archive: yes X-Seq: 2953 Received: (qmail 15291 invoked from network); 6 Mar 2000 21:14:43 -0000 From: mkkwong@lucent.com Original-From: kwong@marconi.ih.lucent.com Message-Id: <200003062114.PAA01448@w-kwong.ih.lucent.com> Subject: some directory changing tools to share To: zsh-users@sunsite.auc.dk Date: Mon, 6 Mar 2000 15:14:04 -0600 (CST) X-Mailer: ELM [version 2.5 PL2] MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit All, I like zsh very much. I have learned a lot by being in this mailing list. I hope I can give something back by sharing some tools that I wrote and which I have tried for quite a while. I find them really useful in increasing my efficiency and productivity. My purpose is twofold. First, I hope that someone else may benefit from the tools, as I have. Second, someone may be able to improve them. I try to add improvements as the needs arise, but there are still imperfections that I simply tolerate for lack of time and patience. Also my number 1 objective to get the tools to work, so there are definitely rooms for better design or more flexibility. Any suggestions for enhancement or bug reports will definitely be welcome. Of course, if you simply like the tools, drop me a line of encouragement. The documentation below is somewhat long because I wrote it in the form a tutorial and sometimes I try to explain why some features are needed. But believe me, the tools are useful and it is worth reading on. Efficient Tools to Change Dir ============================= This is a set of tools to help one navigate through a huge directory system. The objective is to save typing (keystrokes). I have used them ======================== in my work environment (i.e., in the real world, not just theoretically). I sometimes like to describe to others that this is a LAZY man's "cd". In reality, it is not because I am really lazy or that I can't type fast enough. It is a matter efficiency. Whatever small amount of time I can save here, I can use that towards more productive work. I don't see any real benefit in being able to remember a long directory name and to type the entirety of it extremely fast, if one can achieve exactly the same result by typing only a third as much (and equally extremely fast). So much for commercial. Let's get to the meat. Installation ============ If you want to try out the tools: 1. Save the following code snippet in a file called "ktools" (or any other name you like). 2. Make sure you don't have your own aliases that conflict with the commands that I use: c, d, sd, unsd, drs. If you do, read the section "Command Name Conflicts" below. 3. cd to the directory containing the file "ktools"; source the file using the command ". ktools". 4. Try out the commands as described below. I know most people will frown on my codes because I don't write them in a neatly documented and traditional way. I did not originally mean to write it for others to read - all it matters to me is that they work. If enough people like the tools, I'll be glad to shape up the codes. In reality, the tools are not specific to "zsh". With some (slight, mostly syntactic) modifications, I have made them work in "ksh". ######### cut here; put in file "ktools" or .zshrc ############### function c { [ "$1" = "" ] && return ! [ $1 = . ] && ! [ $1 = .. ] && ! [ $1 = ... ] && [ -d $1 ] && { dirname=$1 shift } || dirname=`pwd` [ "$1" = + ] && { flag=1 shift } || flag=0 for _j do _j=${_j%/} _tmp=0 case $_j in .) dirname=$dirname/.. continue ;; ..) dirname=$dirname/../.. continue ;; ...) dirname=$dirname/../../.. continue ;; *) [ -d $dirname/$_j ] && arg=$_j || arg=`/bin/ls -a $dirname| grep -i "^$_j"` [ "$arg" ] || break ;; esac for _i in $arg do [ -d $dirname/$_i ] && { dirname=$dirname/$_i _tmp=1 break } done done if ( [ $dirname != $PWD ] && [ $flag = 0 ] ) || [ "$_tmp" = 1 ] then cd $dirname elif [ "$2" != . ] then c + . $* fi } function sd { loadn; var=_dir$1; eval $var=${2:-$PWD}; saven } function unsd { for _i; do sed "/^_dir$_i/d" $HOME/.dirnames > $HOME/.v; /bin/mv $HOME/.v $HOME/.dirnames; done } function d { if [ $1 ]; then if [ $1 = . ]; then cd $_dir; elif [ $1 = - ]; then dm $2; else dirname=`grep "^_dir$1" $HOME/.dirnames | sed '1q' | sed 's/.*=//'` [ $dirname ] || return; shift; c $dirname $*; fi; else dm; fi; } function dm { drs $1; echo -n "enter short name: "; read a b; case $a in ""|.) cd $_dir;; =) ;; -*) b="`echo $a | sed 's/-//'` $b"; eval unsd $b;; *) d $a $b;; esac } function drs { echo; if [ $1 ]; then grep -i $1 $HOME/.dirnames | sed -e 's/^_dir//' -e 's/=/ /'; else cat $HOME/.dirnames $_1 | sed -e 's/^_dir//' -e 's/=/ /'; fi; echo ;} alias d-='d -' alias saven='set | grep "^_dir" > $HOME/.dirnames' alias loadn='. $HOME/.dirnames' alias c.='c .' alias c..='c ..' alias c...='c ...' alias ch='c ~' alias cm='c ~/Mail' alias P='c ~/Perl' ####################### end "ktools" ############################# Command Name Conflicts ====================== The following is a list of command names used in the tool: P c c. c.. c... ch cm d d- dm drs loadn saven sd unsd If you have been using any of these names for your own commands or aliases, you have 2 options: (1) change your command and alias names, or (2) change those in the above tools. You know my preference, but it is your decision. Sometimes, you may not have knowingly defined commands or aliases that conflict with the ktools names - these may have been defined systemwide by default in your environment. In any way, if a command in ktools does not behave as described here, the first thing to look for is whether there is a hidden command name conflict. In "zsh", the command "which" will reveal how a command is defined, e.g. "which c" which shown "c" as a function definition or alias; compare that with the one in the file ktools. If the output of "which" does not match the definition in ktools, you have a conflict and you must change one of the names. If you add the following lines to the beginning of ktools, they will detect any name conflicts and temporarily override the previously existing commands to let you test run ktools. #################################################################### for i in P c c. c.. c... ch cm d d- dm drs loadn saven sd unsd do case `which $i` in *\ not\ found) ;; *:\ aliased\ to\ *) echo; echo "**** previous alias for $i disabled"; which $i; unalias $i;; *) echo; echo "**** previous command $i no longer accessible" which $i esac done #################################################################### But you will not be able to access the previous commands (which you may not need at all). That is why I suggest testing out the tools for a period of time until you are satisfied that they are useful and there are no conflicts. Then you can include the ktools codes in the ".zshrc" to be invoked automatically at login. Simple Dir Changing =================== Although the code snippet is not that long, there are more than just a couple of features and I'll describe them one by one. Suppose you are currently in a directory and it has the following subdirectories: Doc Faq Info Letters Logs Mail Perl bin mail paper public (regular non-directory files are not listed) You notice that I like to capitalize my directory names whenever I can (a trick that I learned I forgot where - so that the "ls" output puts all these directories at the beginning). Unfortunately, there are always a few exceptions, perhaps because I want to be compatible with my colleagues, or because some directories are created by some software that is out of my control. Now suppose I want to change dir to "Letters". The conventional way is "cd Letters". The more savvy zsh user may have used "cd Le*" or "cd L" (completion), but neither one of these works well if there are other non-directory filenames that also begins with "Le" (you can get around one of the problems by redefining the completion rules for "cd"). Using my tool, you just type c l Rule 1: "c" picks the first (lexicographical order) directory name that ^^^^^^ starts with "l" (case insensitive). See later rules for exceptions. So you never need to press (one keystroke saved) and you never need to remember the entire name (is it Doc or Docs, Letter or Letters?) Other examples: "c lo" goes to "Logs", "c p" to "Perl", "c pa" to "paper" and "c pu" to "public". Plan Directory Names Wisely =========================== You don't need to be told that "c" works best if every subdirectory starts with a different character (case insensitive). If that is not possible, at least avoid having multiple names that have the same first 2 characters. Especially avoid having "Mail" and "mail" in the same directory as in the above example. Think: how do you go to "mail" using "c". Sometimes twisting the directory names a little can help. For instance, if you have 3 subdirectories named "Test1", "Test2", "Test3", change them to "1Test", "2Test", and "3Test". Recursive Use ============= Rule 1 works recursively down the directory tree one level at a time, with unlimited depth. For instance, if "Perl" has a subdirectory "Test" which in turn has a subdirectory "Gui" (assuming that "t" and "g" identities "Test" and "Gui" using Rule 1), then c p t g takes you all the way to Perl/Test/Gui. If that is a directory that you frequent a lot, soon you will discover the correct sequence (later we will learn other even shorter ways). Rule of Exact Match - and Jumping to a Directory Far Away ========================================================= One exception to Rule 1 is that Rule 2: if there is an exact match (both case sensitiveness AND entire ^^^^^^ name), then "c" will pick that over Rule 1. Rule 2 applies to any of the arguments at any level. For instance, c mail will change to "mail" instead of "Mail". However, "c mai" still gives you "Mail" because "mai" is not an exact match for "mail". The major use of Rule 2, however, is in jumping to a directory that can be far away in the whole directory tree. For instance, you can be any where, and c ~ p t will bring to you your home directory (~ is an exact match) and then traverse down the tree using Rule 1 to match "p" and "t". (If the example cited above is actually under your home directory, then this will bring you to "Perl/Test"). You can use that to go to directories that are not even under you home directory, e.g, c / us op l (to /usr/openwin/lib) c ~john bi (to /home/john/bin) You must have some favorite directories that you frequent often. A good tip is to define aliases to jump to those directories. The ktools above has several examples: ch (c ~) jumps to home directory c. (c ..) jumps to parent directory (similarly c.. c...) P (c ~/Perl) jumps to a favorite directory I have aliases for almost all my favorite directories. If you've ever worked in a large software development environment, you are familiar with the practice that multiple versions of the software codes are kept in various nodes: official, testing, development, etc. These nodes have almost identical directory structures under them. The real names of these nodes are normally stored in environment variables such as $OFC, $TST, $DEV, etc., which are automatically set by some utility either at login or when invoked manually. You can define aliases such as: alias co='c $OFC' alias ct='c $TST' alias dev='c $DEV' to facilitate moving around from one node to another. Actually, if you really want to be able to navigate efficiently in such a system, you need additional tools that exploits the fact that these node have almost identical structures. (For example, to from one directory under $DEV to the corresponding directory under $OFC. The usual way is "cd $DEV $OFC" and a more efficient way is "n o" if you have defined the appropriate command "n"). Those additional tools are rather specific to the actual environment and I'll skip them. Up, Up You Go (. .. ...) ======================== You have an alias X to jump to a favorite directory /abc/def/gh/ijkl/xyz. But you only need to go to /abd/def/gh occasionally. It is not worthwhile to define an alias for that (besides, you are running out of letters in the alphabet). You can use X . (to go up to /abc/def/gh/ijk) X .. (to go up to /abc/def/gh) X .. t (to go up to /abc/def/gh and then down to "T@@@" or "t@@@") Setting Directory Aliases (sd) and Jumping to Directory Aliases (d) =================================================================== Assigning an alias to jump to a favorite directory is a good strategy if you know that the directory will be a favorite directory for many years to come. I have a different strategy to deal with directories that may be hot for only a short period of time (e.g. a short project). You want to be able to do something ON THE FLY (rather than having to add a line in .zshrc and to source the file - for every existing window). If you prefer, you can also use this new strategy for more permanent favorite directories. However, the new method has the caveat of permitting accidental overwriting of existing alias names. While you are in the directory to which you want to assign an alias (because you anticipate that you will need to go back to that directory many times in the next 2 weeks), type the command sd ALIAS_STRING where ALIAS_STRING is any string you choose to represent the directory. You can even use an existing directory name or command name and there will be no conflict. If a directory ALIAS using the same string already exists, it will be overwritten. The string need not be related in any way to the actual name of the directory, although that would help you to remember the alias. For example, you may use "kbin" for "~kwong/Bin", or "ow" for "/usr/openwin". Rule d1: As soon as the alias is set with "sd", it is available in any ^^^^^^^ windows, or subsequent logins. There is no need to source any files, or logout and log back in again. To jump to the directory, type d ALIAS We follow similar principles used in the design of "c". Rule d2: You only need to type the beginning portion of the alias string ^^^^^^^ as long as it can be identified as the first one (lexicographical order). Unlike "c", though, "d" is case SENSITIVE. Rule d3: After the alias argument, "d" transmutes into the "c" command. ^^^^^^^ For instance, d kb t will go to "kwong/Bin/Test d kb . p will go to ~kwong/Perl if "kbin" is the first directory alias that begins with "kb" and "Test" is the first subdir under that that begins with "T", and "Perl" is the first directory under ~kwong that begins with "P". I Can't Remember All the Directory Aliases that I Set a Few Months Ago ====================================================================== If you type just "d" by itself, a list of all aliases will be displayed in alphabetical order, and you are prompted to enter the one that you want to jump to. If you have too many aliases, you may want to use the variant dm STRING (dir aliases matching STRING) which will print a list of aliases that contain the string STRING either in the alias or in the complete pathname of the directory. Cleaning Up Directory Aliases ============================= After a while, you would have created too many aliases and many of them are already outdated. I have a command "unsd" to unset the aliases, but it is not very ideal. Currently, the best way is to edit the file ~/.dirnames, delete the lines that you don't need. Then logout and log back in again (any suggestion to get rid of these steps?). The problem is that if you use "d" in any window after you've edited the file, the original .dirnames may be restored and the edited changes may be gone. Caveats ======= For slower machines, "c" or "d" with too many arguments can be a bit slow. Speed is tolerable on my machine and many I have used. If a file server is down and the directories that "c" or "d" need to go to lie on that server, "c" or "d" may hang (ideally they should be able to detect that something is wrong and exit gracefully). ^C may be able to abort the command. ************************************************************************** vim: tw=75