AAnn IInnttrroodduuccttiioonn ttoo tthhee ZZ SShheellll _P_a_u_l _F_a_l_s_t_a_d _p_f_@_z_-_c_o_d_e_._c_o_m _B_a_s _d_e _B_a_k_k_e_r _b_a_s_@_p_h_y_s_._u_v_a_._n_l IInnttrroodduuccttiioonn zzsshh is a shell designed for interactive use, although it is also a powerful scripting language. Many of the useful fea- tures of bash, ksh, and tcsh were incorporated into zzsshh; many original features were added. This document details some of the unique features of zzsshh. It assumes basic knowl- edge of the standard UNIX shells; the intent is to show a reader already familiar with one of the other major shells what makes zzsshh more useful or more powerful. This document is not at all comprehensive; read the manual entry for a description of the shell that is complete and concise, although somewhat overwhelming and devoid of examples. The text will frequently mention options that you can set to change the behaviour of zzsshh. You can set these options with the command %% sseettoopptt _o_p_t_i_o_n_n_a_m_e and unset them again with %% uunnsseettoopptt _o_p_t_i_o_n_n_a_m_e Case is ignored in option names, as are embedded under- scores. FFiilleennaammee GGeenneerraattiioonn Otherwise known as _g_l_o_b_b_i_n_g, filename generation is quite extensive in zzsshh. Of course, it has all the basics: %% llss MMaakkeeffiillee ffiillee..pprroo ffoooo..oo mmaaiinn..oo qq..cc rruunn223344 ssttuuffff bbaarr..oo ffoooo lliinnkk mmoorreessttuuffff rruunn112233 rruunn224400 ssuubb ffiillee..hh ffoooo..cc mmaaiinn..hh ppiippee rruunn22 rruunn330033 %% llss **..cc ffoooo..cc qq..cc %% llss **..[[ccoo]] bbaarr..oo ffoooo..cc ffoooo..oo mmaaiinn..oo qq..cc %% llss ffoooo..?? ffoooo..cc ffoooo..oo -2- %% llss **..[[^^cc]] bbaarr..oo ffiillee..hh ffoooo..oo mmaaiinn..hh mmaaiinn..oo %% llss **..[[^^oohh]] ffoooo..cc qq..cc Also, if the _E_X_T_E_N_D_E_D_G_L_O_B option is set, some new features are activated. For example, the ^^ character negates the pattern following it: %% sseettoopptt eexxtteennddeeddgglloobb %% llss --dd ^^**..cc MMaakkeeffiillee ffiillee..pprroo lliinnkk mmoorreessttuuffff rruunn22 rruunn330033 bbaarr..oo ffoooo mmaaiinn..hh ppiippee rruunn223344 ssttuuffff ffiillee..hh ffoooo..oo mmaaiinn..oo rruunn112233 rruunn224400 ssuubb %% llss --dd ^^**..** MMaakkeeffiillee lliinnkk ppiippee rruunn22 rruunn224400 ssttuuffff ffoooo mmoorreessttuuffff rruunn112233 rruunn223344 rruunn330033 ssuubb %% llss --dd ^^MMaakkeeffiillee bbaarr..oo ffoooo lliinnkk mmoorreessttuuffff rruunn112233 rruunn224400 ssuubb ffiillee..hh ffoooo..cc mmaaiinn..hh ppiippee rruunn22 rruunn330033 ffiillee..pprroo ffoooo..oo mmaaiinn..oo qq..cc rruunn223344 ssttuuffff %% llss --dd **..^^cc ..rrhhoossttss bbaarr..oo ffiillee..hh ffiillee..pprroo ffoooo..oo mmaaiinn..hh mmaaiinn..oo An expression of the form <<_x-_y>> matches a range of integers: %% llss rruunn<<220000--330000>> rruunn223344 rruunn224400 %% llss rruunn<<330000--440000>> rruunn330033 %% llss rruunn<<--220000>> rruunn112233 rruunn22 %% llss rruunn<<330000-->> rruunn330033 %% llss rruunn<<>> rruunn112233 rruunn22 rruunn223344 rruunn224400 rruunn330033 The _N_U_M_E_R_I_C_G_L_O_B_S_O_R_T option will sort files with numbers according to the number. This will not work with llss as it resorts its arguments: %% sseettoopptt nnuummeerriiccgglloobbssoorrtt %% eecchhoo rruunn<<>> rruunn22 rruunn112233 rruunn223344 rruunn224400 rruunn330033 Grouping is possible: %% llss ((ffoooo||bbaarr))..** bbaarr..oo ffoooo..cc ffoooo..oo %% llss **..((cc||oo||pprroo)) bbaarr..oo ffiillee..pprroo ffoooo..cc ffoooo..oo mmaaiinn..oo qq..cc Also, the string ****// forces a recursive search of subdirec- tories: -3- %% llss --RR MMaakkeeffiillee ffiillee..pprroo ffoooo..oo mmaaiinn..oo qq..cc rruunn223344 ssttuuffff bbaarr..oo ffoooo lliinnkk mmoorreessttuuffff rruunn112233 rruunn224400 ssuubb ffiillee..hh ffoooo..cc mmaaiinn..hh ppiippee rruunn22 rruunn330033 mmoorreessttuuffff:: ssttuuffff:: ffiillee xxxxxx yyyyyy ssttuuffff//xxxxxx:: ffoooobbaarr ssttuuffff//yyyyyy:: ffrroobbaarr %% llss ****//**bbaarr ssttuuffff//xxxxxx//ffoooobbaarr ssttuuffff//yyyyyy//ffrroobbaarr %% llss ****//ff** ffiillee..hh ffoooo ffoooo..oo ssttuuffff//xxxxxx//ffoooobbaarr ffiillee..pprroo ffoooo..cc ssttuuffff//ffiillee ssttuuffff//yyyyyy//ffrroobbaarr %% llss **bbaarr** bbaarr..oo %% llss ****//**bbaarr** bbaarr..oo ssttuuffff//xxxxxx//ffoooobbaarr ssttuuffff//yyyyyy//ffrroobbaarr %% llss ssttuuffff//****//**bbaarr** ssttuuffff//xxxxxx//ffoooobbaarr ssttuuffff//yyyyyy//ffrroobbaarr It is possible to exclude certain files from the patterns using the ~ character. A pattern of the form **..cc~~bbaarr..cc lists all files matching **..cc, except for the file bbaarr..cc. %% llss **..cc ffoooo..cc ffoooobb..cc bbaarr..cc %% llss **..cc~~bbaarr..cc ffoooo..cc ffoooobb..cc %% llss **..cc~~ff** bbaarr..cc One can add a number of _q_u_a_l_i_f_i_e_r_s to the end of any of these patterns, to restrict matches to certain file types. A qualified pattern is of the form _p_a_t_t_e_r_n((...)) with single-character qualifiers inside the parentheses. %% aalliiaass ll==''llss --ddFF'' %% ll ** MMaakkeeffiillee ffoooo** mmaaiinn..hh qq..cc rruunn224400 bbaarr..oo ffoooo..cc mmaaiinn..oo rruunn112233 rruunn330033 ffiillee..hh ffoooo..oo mmoorreessttuuffff// rruunn22 ssttuuffff// ffiillee..pprroo lliinnkk@@ ppiippee rruunn223344 ssuubb -4- %% ll **((//)) mmoorreessttuuffff// ssttuuffff// %% ll **((@@)) lliinnkk@@ %% ll **((**)) ffoooo** lliinnkk@@ mmoorreessttuuffff// ssttuuffff// %% ll **((xx)) ffoooo** lliinnkk@@ mmoorreessttuuffff// ssttuuffff// %% ll **((XX)) ffoooo** lliinnkk@@ mmoorreessttuuffff// ssttuuffff// %% ll **((RR)) bbaarr..oo ffoooo** lliinnkk@@ mmoorreessttuuffff// rruunn112233 rruunn224400 ffiillee..hh ffoooo..cc mmaaiinn..hh ppiippee rruunn22 rruunn330033 ffiillee..pprroo ffoooo..oo mmaaiinn..oo qq..cc rruunn223344 ssttuuffff// Note that **((xx)) and **((**)) both match executables. **((XX)) matches files executable by others, as opposed to **((xx)), which matches files executable by the owner. **((RR)) and **((rr)) match readable files; **((WW)) and **((ww)), which checks for writable files. **((WW)) is especially important, since it checks for world-writable files: %% ll **((ww)) bbaarr..oo ffoooo** lliinnkk@@ mmoorreessttuuffff// rruunn112233 rruunn224400 ffiillee..hh ffoooo..cc mmaaiinn..hh ppiippee rruunn22 rruunn330033 ffiillee..pprroo ffoooo..oo mmaaiinn..oo qq..cc rruunn223344 ssttuuffff// %% ll **((WW)) lliinnkk@@ rruunn224400 %% ll --ll lliinnkk rruunn224400 llrrwwxxrrwwxxrrwwxx 11 ppffaallssttaadd 1100 MMaayy 2233 1188::1122 lliinnkk -->> //uussrr//bbiinn// --rrww--rrww--rrww-- 11 ppffaallssttaadd 00 MMaayy 2233 1188::1122 rruunn224400 If you want to have all the files of a certain type as well as all symbolic links pointing to files of that type, prefix the qualifier with a --: %% ll **((--//)) lliinnkk@@ mmoorreessttuuffff// ssttuuffff// You can filter out the symbolic links with the ^^ character: %% ll **((WW^^@@)) rruunn224400 %% ll **((xx)) ffoooo** lliinnkk@@ mmoorreessttuuffff// ssttuuffff// %% ll **((xx^^@@//)) ffoooo** To find all plain files, you can use ..: %% ll **((..)) MMaakkeeffiillee ffiillee..hh ffoooo** ffoooo..oo mmaaiinn..oo rruunn112233 rruunn223344 rruunn330033 bbaarr..oo ffiillee..pprroo ffoooo..cc mmaaiinn..hh qq..cc rruunn22 rruunn224400 ssuubb %% ll **((^^..)) -5- lliinnkk@@ mmoorreessttuuffff// ppiippee ssttuuffff// %% ll ss**((..)) ssttuuffff// ssuubb %% ll **((pp)) ppiippee %% ll --ll **((pp)) pprrww--rr----rr---- 11 ppffaallssttaadd 00 MMaayy 2233 1188::1122 ppiippee **((UU)) matches all files owned by you. To search for all files not owned by you, use **((^^UU)): %% ll --ll **((^^UU)) --rrww-------------- 11 ssuubbbbaarraaoo 2299 MMaayy 2233 1188::1133 ssuubb This searches for setuid files: %% ll --ll **((ss)) --rrwwssrr--xxrr--xx 11 ppffaallssttaadd 1166 MMaayy 2233 1188::1122 ffoooo** This checks for a certain user's files: %% ll --ll **((uu[[ssuubbbbaarraaoo]])) --rrww-------------- 11 ssuubbbbaarraaoo 2299 MMaayy 2233 1188::1133 ssuubb SSttaarrttuupp FFiilleess There are five startup files that zzsshh will read commands from: $$ZZDDOOTTDDIIRR//..zzsshheennvv $$ZZDDOOTTDDIIRR//..zzpprrooffiillee $$ZZDDOOTTDDIIRR//..zzsshhrrcc $$ZZDDOOTTDDIIRR//..zzllooggiinn $$ZZDDOOTTDDIIRR//..zzllooggoouutt If ZZDDOOTTDDIIRR is not set, then the value of HHOOMMEE is used; this is the usual case. ..zzsshheennvv is sourced on all invocations of the shell, unless the --ff option is set. It should contain commands to set the command search path, plus other important environment vari- ables. ..zzsshheennvv should not contain commands that produce output or assume the shell is attached to a tty. ..zzsshhrrcc is sourced in interactive shells. It should contain commands to set up aliases, functions, options, key bind- ings, etc. ..zzllooggiinn is sourced in login shells. It should contain com- mands that should be executed only in login shells. ..zzlloo-- ggoouutt is sourced when login shells exit. ..zzpprrooffiillee is simi- lar to ..zzllooggiinn, except that it is sourced before ..zzsshhrrcc. ..zzpprrooffiillee is meant as an alternative to ..zzllooggiinn for ksh -6- fans; the two are not intended to be used together, although this could certainly be done if desired. ..zzllooggiinn is not the place for alias definitions, options, environment variable settings, etc.; as a general rule, it should not change the shell environment at all. Rather, it should be used to set the terminal type and run a series of external commands (ffoorrttuunnee, mmssggss, etc). SShheellll FFuunnccttiioonnss zzsshh also allows you to create your own commands by defining shell functions. For example: %% yypp (()) {{ >> yyppmmaattcchh $$11 ppaasssswwdd..bbyynnaammee >> }} %% yypp ppffaallssttaadd ppffaallssttaadd::**::33556644::3355::PPaauull JJoohhnn FFaallssttaadd:://uu//ppffaallssttaadd:://uussrr//pprriinncceettoonn//bbiinn//zzsshh This function looks up a user in the NIS password map. The $$11 expands to the first argument to yypp. The function could have been equivalently defined in one of the following ways: %% ffuunnccttiioonn yypp {{ >> yyppmmaattcchh $$11 ppaasssswwdd..bbyynnaammee >> }} %% ffuunnccttiioonn yypp (()) {{ >> yyppmmaattcchh $$11 ppaasssswwdd..bbyynnaammee >> }} %% ffuunnccttiioonn yypp (()) yyppmmaattcchh $$11 ppaasssswwdd..bbyynnaammee Note that aliases are expanded when the function definition is parsed, not when the function is executed. For example: %% aalliiaass yyppmmaattcchh==eecchhoo %% yypp ppffaallssttaadd ppffaallssttaadd::**::33556644::3355::PPaauull JJoohhnn FFaallssttaadd:://uu//ppffaallssttaadd:://uussrr//pprriinncceettoonn//bbiinn//zzsshh Since the alias was defined after the function was parsed, it has no effect on the function's execution. However, if we define the function again with the alias in place: %% ffuunnccttiioonn yypp (()) {{ yyppmmaattcchh $$11 ppaasssswwdd..bbyynnaammee }} %% yypp ppffaallssttaadd ppffaallssttaadd ppaasssswwdd..bbyynnaammee it is parsed with the new alias definition in place. There- fore, in general you must define aliases before functions. We can make the function take multiple arguments: %% uunnaalliiaass yyppmmaattcchh %% yypp (()) {{ >> ffoorr ii -7- >> ddoo yyppmmaattcchh $$ii ppaasssswwdd..bbyynnaammee >> ddoonnee >> }} %% yypp ppffaallssttaadd ssuubbbbaarraaoo ssuukktthhnnkkrr ppffaallssttaadd::**::33556644::3355::PPaauull JJoohhnn FFaallssttaadd:://uu//ppffaallssttaadd:://uussrr//pprriinncceettoonn//bbiinn//zzsshh ssuubbbbaarraaoo::**::33333388::3355::KKaarrttiikk SSuubbbbaarraaoo:://uu//ssuubbbbaarraaoo:://uussrr//pprriinncceettoonn//bbiinn//zzsshh ssuukktthhnnkkrr::**::11226677::3355::RRaahhuull SSuukktthhaannkkaarr:://uu//ssuukktthhnnkkrr:://uussrr//pprriinncceettoonn//bbiinn//ttccsshh The ffoorr ii loops through each of the function's arguments, setting ii equal to each of them in turn. We can also make the function do something sensible if no arguments are given: %% yypp (()) {{ >> iiff (((( $$## ==== 00 )))) >> tthheenn eecchhoo uussaaggee:: yypp nnaammee ......;; ffii >> ffoorr ii;; ddoo yyppmmaattcchh $$ii ppaasssswwdd..bbyynnaammee;; ddoonnee >> }} %% yypp uussaaggee:: yypp nnaammee ...... %% yypp ppffaallssttaadd ssuukktthhnnkkrr ppffaallssttaadd::**::33556644::3355::PPaauull JJoohhnn FFaallssttaadd:://uu//ppffaallssttaadd:://uussrr//pprriinncceettoonn//bbiinn//zzsshh ssuukktthhnnkkrr::**::11226677::3355::RRaahhuull SSuukktthhaannkkaarr:://uu//ssuukktthhnnkkrr:://uussrr//pprriinncceettoonn//bbiinn//ttccsshh $$## is the number of arguments supplied to the function. If it is equal to zero, we print a usage message; otherwise, we loop through the arguments, and yyppmmaattcchh all of them. Here's a function that selects a random line from a file: %% rraannddlliinnee (()) {{ >> iinntteeggeerr zz==$$((wwcc --ll <<$$11)) >> sseedd --nn $$[[RRAANNDDOOMM %% zz ++ 11]]pp $$11 >> }} %% rraannddlliinnee //eettcc//mmoottdd PPHHOOEENNIIXX WWIILLLL BBEE DDOOWWNN bbrriieeffllyy FFrriiddaayy mmoorrnniinngg,, 55//2244//9911 ffrroomm 88 AAMM ttoo %% rraannddlliinnee //eettcc//mmoottdd SSuunnOOSS RReelleeaassee 44..11..11 ((PPHHOOEENNIIXX)) ##1199:: TTuuee MMaayy 1144 1199::0033::1155 EEDDTT 11999911 %% rraannddlliinnee //eettcc//mmoottdd || PPlleeaassee uussee tthhee ""mmssggss"" ccoommmmaanndd ttoo rreeaadd aannnnoouunncceemmeennttss.. RReeffeerr ttoo tthhee || %% eecchhoo $$zz %% rraannddlliinnee has a local variable, zz, that holds the number of lines in the file. $$[[RRAANNDDOOMM %% zz ++ 11]] expands to a random number between 1 and zz. An expression of the form $$[[...]] expands to the value of the arithmetic expression within the brackets, and the RRAANNDDOOMM variable returns a random number each time it is referenced. %% is the modulus operator, as in C. Therefore, sseedd --nn $$[[RRAANNDDOOMM%%zz++11]]pp picks a random line from its input, from 1 to zz. -8- Function definitions can be viewed with the ffuunnccttiioonnss builtin: %% ffuunnccttiioonnss rraannddlliinnee rraannddlliinnee (()) {{ iinntteeggeerr zz==$$((wwcc --ll <<$$11)) sseedd --nn $$[[RRAANNDDOOMM %% zz ++ 11]]pp $$11 }} %% ffuunnccttiioonnss yypp (()) {{ iiff lleett $$## ==== 00 tthheenn eecchhoo uussaaggee:: yypp nnaammee ...... ffii ffoorr ii ddoo yyppmmaattcchh $$ii ppaasssswwdd..bbyynnaammee ddoonnee }} rraannddlliinnee (()) {{ iinntteeggeerr zz==$$((wwcc --ll <<$$11)) sseedd --nn $$[[RRAANNDDOOMM %% zz ++ 11]]pp $$11 }} Here's another one: %% ccxx (()) {{ cchhmmoodd ++xx $$** }} %% llss --ll ffoooo bbaarr --rrww--rr----rr---- 11 ppffaallssttaadd 2299 MMaayy 2244 0044::3388 bbaarr --rrww--rr----rr---- 11 ppffaallssttaadd 2299 MMaayy 2244 0044::3388 ffoooo %% ccxx ffoooo bbaarr %% llss --ll ffoooo bbaarr --rrwwxxrr--xxrr--xx 11 ppffaallssttaadd 2299 MMaayy 2244 0044::3388 bbaarr --rrwwxxrr--xxrr--xx 11 ppffaallssttaadd 2299 MMaayy 2244 0044::3388 ffoooo Note that this could also have been implemented as an alias: %% cchhmmoodd 664444 ffoooo bbaarr %% aalliiaass ccxx==''cchhmmoodd ++xx'' %% ccxx ffoooo bbaarr %% llss --ll ffoooo bbaarr --rrwwxxrr--xxrr--xx 11 ppffaallssttaadd 2299 MMaayy 2244 0044::3388 bbaarr --rrwwxxrr--xxrr--xx 11 ppffaallssttaadd 2299 MMaayy 2244 0044::3388 ffoooo Instead of defining a lot of functions in your ..zzsshhrrcc, all of which you may not use, it is often better to use the aauuttoollooaadd builtin. The idea is, you create a directory where -9- function definitions are stored, declare the names in your ..zzsshhrrcc, and tell the shell where to look for them. Whenever you reference a function, the shell will automatically load it into memory. %% mmkkddiirr //ttmmpp//ffuunnss %% ccaatt >>//ttmmpp//ffuunnss//yypp yyppmmaattcchh $$11 ppaasssswwdd..bbyynnaammee ^^DD %% ccaatt >>//ttmmpp//ffuunnss//ccxx cchhmmoodd ++xx $$** ^^DD %% FFPPAATTHH==//ttmmpp//ffuunnss %% aauuttoollooaadd ccxx yypp %% ffuunnccttiioonnss ccxx yypp uunnddeeffiinneedd ccxx (()) uunnddeeffiinneedd yypp (()) %% cchhmmoodd 775555 //ttmmpp//ffuunnss//{{ccxx,,yypp}} %% yypp eeggssiirreerr eeggssiirreerr::**::33221144::3355::EEmmiinn GGuunn SSiirreerr:://uu//eeggssiirreerr:://bbiinn//sshh %% ffuunnccttiioonnss yypp yypp (()) {{ yyppmmaattcchh $$11 ppaasssswwdd..bbyynnaammee }} This idea has other benefits. By adding a ##!! header to the files, you can make them double as shell scripts. (Although it is faster to use them as functions, since a separate pro- cess is not created.) %% eedd //ttmmpp//ffuunnss//yypp 2255 ii ##!! //uussrr//llooccaall//bbiinn//zzsshh ww 4422 qq %% <> '' ~~>> ccdd ssrrcc -10- ~~//ssrrcc>> the shell will print the current directory in the prompt, using the ~~ character. However, zzsshh is smarter than most other shells in this respect: ~~//ssrrcc>> ccdd ~~ssuubbbbaarraaoo ~~ssuubbbbaarraaoo>> ccdd ~~mmaarruucchhcckk ~~mmaarruucchhcckk>> ccdd lliibb ~~mmaarruucchhcckk//lliibb>> ccdd ffuunn ~~mmaarruucchhcckk//lliibb//ffuunn>> ffoooo==//uussrr//pprriinncceettoonn//ccoommmmoonn//ssrrcc ~~mmaarruucchhcckk//lliibb//ffuunn>> ccdd ~~ffoooo ~~ffoooo>> ccdd .... //uussrr//pprriinncceettoonn//ccoommmmoonn>> ccdd ssrrcc ~~ffoooo>> ccdd nneewwss//nnnnttpp ~~ffoooo//nneewwss//nnnnttpp>> ccdd iinneewwss ~~ffoooo//nneewwss//nnnnttpp//iinneewwss>> Note that zzsshh prints _o_t_h_e_r users' directories in the form ~~uusseerr. Also note that you can set a parameter and use it as a directory name; zzsshh will act as if ffoooo is a user with the login directory //uussrr//pprriinncceettoonn//ccoommmmoonn//ssrrcc. This is conve- nient, especially if you're sick of seeing prompts like this: pphhooeenniixx:://uussrr//pprriinncceettoonn//ccoommmmoonn//ssrrcc//XX..VV1111RR44//ccoonnttrriibb//cclliieennttss//xxvv//ddooccss>> If you get stuck in this position, you can give the current directory a short name, like this: //uussrr//pprriinncceettoonn//ccoommmmoonn//ssrrcc//nneewwss//nnnnttpp//iinneewwss>> iinneewwss==$$PPWWDD //uussrr//pprriinncceettoonn//ccoommmmoonn//ssrrcc//nneewwss//nnnnttpp//iinneewwss>> eecchhoo ~~iinneewwss //uussrr//pprriinncceettoonn//ccoommmmoonn//ssrrcc//nneewwss//nnnnttpp//iinneewwss ~~iinneewwss>> When you reference a directory in the form ~~iinneewwss, the shell assumes that you want the directory displayed in this form; thus simply typing eecchhoo ~~iinneewwss or ccdd ~~iinneewwss causes the prompt to be shortened. You can define a shell function for this purpose: ~~iinneewwss>> nnaammeeddiirr (()) {{ $$11==$$PPWWDD ;; :: ~~$$11 }} ~~iinneewwss>> ccdd //uussrr//pprriinncceettoonn//bbiinn //uussrr//pprriinncceettoonn//bbiinn>> nnaammeeddiirr ppbbiinn ~~ppbbiinn>> ccdd //vvaarr//ssppooooll//mmaaiill //vvaarr//ssppooooll//mmaaiill>> nnaammeeddiirr ssppooooll ~~ssppooooll>> ccdd ..mmssggss ~~ssppooooll//..mmssggss>> You may want to add this one-line function to your ..zzsshhrrcc. zzsshh can also put the current directory in your title bar, if you are using a windowing system. One way to do this is with the cchhppwwdd function, which is automatically executed by -11- the shell whenever you change directory. If you are using xterm, this will work: cchhppwwdd (()) {{ pprriinntt --PPnn ''^^[[]]22;;%%~~^^GG'' }} The --PP option tells pprriinntt to treat its arguments like a prompt string; otherwise the %%~~ would not be expanded. The --nn option suppresses the terminating newline, as with eecchhoo. If you are using an IRIS wwsshh, do this: cchhppwwdd (()) {{ pprriinntt --PPnn ''\\22220011..yy%%~~\\223344'' }} The pprriinntt --DD command has other uses. For example, to print the current directory to standard output in short form, you can do this: %% pprriinntt --DD $$PPWWDD ~~ssuubbbbaarraaoo//ssrrcc and to print each component of the path in short form: %% pprriinntt --DD $$ppaatthh //bbiinn //uussrr//bbiinn ~~llooccbbiinn ~~llooccbbiinn//XX1111 ~~//bbiinn DDiirreeccttoorryy SSttaacckkss If you use csh, you may know about directory stacks. The ppuusshhdd command puts the current directory on the stack, and changes to a new directory; the ppooppdd command pops a direc- tory off the stack and changes to it. pphhooeenniixx%% ccdd pphhooeenniixx%% PPRROOMMPPTT==''ZZ %%~~>> '' ZZ ~~>> ppuusshhdd //ttmmpp //ttmmpp ~~ ZZ //ttmmpp>> ppuusshhdd //uussrr//eettcc //uussrr//eettcc //ttmmpp ~~ ZZ //uussrr//eettcc>> ppuusshhdd //uussrr//bbiinn //uussrr//bbiinn //uussrr//eettcc //ttmmpp ~~ ZZ //uussrr//bbiinn>> ppooppdd //uussrr//eettcc //ttmmpp ~~ ZZ //uussrr//eettcc>> ppooppdd //ttmmpp ~~ ZZ //ttmmpp>> ppuusshhdd //eettcc //eettcc //ttmmpp ~~ ZZ //eettcc>> ppooppdd //ttmmpp ~~ zzsshh's directory stack commands work similarly. One differ- ence is the way ppuusshhdd is handled if no arguments are given. As in csh, this exchanges the top two elements of the direc- tory stack: -12- ZZ //ttmmpp>> ddiirrss //ttmmpp ~~ ZZ //ttmmpp>> ppuusshhdd ~~ //ttmmpp unless the stack only has one entry: ZZ ~~>> ppooppdd //ttmmpp ZZ //ttmmpp>> ddiirrss //ttmmpp ZZ //ttmmpp>> ppuusshhdd ~~ //ttmmpp ZZ ~~>> or unless the _P_U_S_H_D_T_O_H_O_M_E option is set: ZZ ~~>> sseettoopptt ppuusshhddttoohhoommee ZZ ~~>> ppuusshhdd ~~ ~~ //ttmmpp As an alternative to using directory stacks in this manner, we can get something like a _d_i_r_e_c_t_o_r_y _h_i_s_t_o_r_y by setting a few more options and parameters: ~~>> DDIIRRSSTTAACCKKSSIIZZEE==88 ~~>> sseettoopptt aauuttooppuusshhdd ppuusshhddmmiinnuuss ppuusshhddssiilleenntt ppuusshhddttoohhoommee ~~>> aalliiaass ddhh==''ddiirrss --vv'' ~~>> ccdd //ttmmpp //ttmmpp>> ccdd //uussrr //uussrr>> ccdd bbiinn //uussrr//bbiinn>> ccdd ....//ppuubb //uussrr//ppuubb>> ddhh 00 //uussrr//ppuubb 11 //uussrr//bbiinn 22 //uussrr 33 //ttmmpp 44 ~~ //uussrr//ppuubb>> ccdd --33 //ttmmpp>> ddhh 00 //ttmmpp 11 //uussrr//ppuubb 22 //uussrr//bbiinn 33 //uussrr 44 ~~ //ttmmpp>> llss ==22//ddff //uussrr//bbiinn//ddff //ttmmpp>> ccdd --44 ~~>> Note that ==22 expanded to the second directory in the history list, and that ccdd --33 recalled the third directory in the list. -13- You may be wondering what all those options do. _A_U_T_O_P_U_S_H_D made ccdd act like ppuusshhdd. (aalliiaass ccdd==ppuusshhdd is not sufficient, for various reasons.) _P_U_S_H_D_M_I_N_U_S swapped the meaning of ccdd ++11 and ccdd --11; we want them to mean the opposite of what they mean in csh, because it makes more sense in this scheme, and it's easier to type: ~~>> ddhh 00 ~~ 11 //ttmmpp 22 //uussrr//ppuubb 33 //uussrr//bbiinn 44 //uussrr ~~>> uunnsseettoopptt ppuusshhddmmiinnuuss ~~>> ccdd ++11 //ttmmpp>> ddhh 00 //ttmmpp 11 ~~ 22 //uussrr//ppuubb 33 //uussrr//bbiinn 44 //uussrr //ttmmpp>> ccdd ++22 //uussrr//ppuubb>> _P_U_S_H_D_S_I_L_E_N_T keeps the shell from printing the directory stack each time we do a ccdd, and _P_U_S_H_D_T_O_H_O_M_E we mentioned earlier: //uussrr//ppuubb>> uunnsseettoopptt ppuusshhddssiilleenntt //uussrr//ppuubb>> ccdd //eettcc //eettcc //uussrr//ppuubb //ttmmpp ~~ //uussrr//bbiinn //uussrr //eettcc>> ccdd ~~ //eettcc //uussrr//ppuubb //ttmmpp ~~ //uussrr//bbiinn //uussrr ~~>> uunnsseettoopptt ppuusshhddttoohhoommee ~~>> ccdd //eettcc ~~ //uussrr//ppuubb //ttmmpp ~~ //uussrr//bbiinn //uussrr //eettcc>> DDIIRRSSTTAACCKKSSIIZZEE keeps the directory stack from getting too large, much like _H_I_S_T_S_I_Z_E: //eettcc>> sseettoopptt ppuusshhddssiilleenntt //eettcc>> ccdd // //>> ccdd // //>> ccdd // //>> ccdd // //>> ccdd // //>> ccdd // //>> ccdd // //>> ccdd // //>> ddhh 00 // 11 // 22 // -14- 33 // 44 // 55 // 66 // 77 // CCoommmmaanndd//PPrroocceessss SSuubbssttiittuuttiioonn Command substitution in zzsshh can take two forms. In the tra- ditional form, a command enclosed in backquotes (``...``) is replaced on the command line with its output. This is the form used by the older shells. Newer shells (like zzsshh) also provide another form, $$((...)). This form is much easier to nest. %% llss --ll ``eecchhoo //vvmmuunniixx`` --rrwwxxrr--xxrr--xx 11 rroooott 11220099770022 MMaayy 1144 1199::0044 //vvmmuunniixx %% llss --ll $$((eecchhoo //vvmmuunniixx)) --rrwwxxrr--xxrr--xx 11 rroooott 11220099770022 MMaayy 1144 1199::0044 //vvmmuunniixx %% wwhhoo || ggrreepp mmaadd ssuubbbbaarraaoo ttttyytt77 MMaayy 2233 1155::0022 ((mmaadd5555ssxx1155..PPrriinnccee)) ppffaallssttaadd ttttyyuu11 MMaayy 2233 1166::2255 ((mmaadd5555ssxx1144..PPrriinnccee)) ssuubbbbaarraaoo ttttyyuu66 MMaayy 2233 1155::0044 ((mmaadd5555ssxx1155..PPrriinnccee)) ppffaallssttaadd ttttyyvv33 MMaayy 2233 1166::2255 ((mmaadd5555ssxx1144..PPrriinnccee)) %% wwhhoo || ggrreepp mmaadd || aawwkk ''{{pprriinntt $$22}}'' ttttyytt77 ttttyyuu11 ttttyyuu66 ttttyyvv33 %% ccdd //ddeevv;; llss --ll $$((wwhhoo || >> ggrreepp $$((eecchhoo mmaadd)) || >> aawwkk ''{{ pprriinntt $$22 }}'')) ccrrwwxx--ww-------- 11 ssuubbbbaarraaoo 2200,, 7711 MMaayy 2233 1188::3355 ttttyytt77 ccrrww----ww-------- 11 ppffaallssttaadd 2200,, 8811 MMaayy 2233 1188::4422 ttttyyuu11 ccrrwwxx--ww-------- 11 ssuubbbbaarraaoo 2200,, 8866 MMaayy 2233 1188::3388 ttttyyuu66 ccrrww----ww-------- 11 ppffaallssttaadd 2200,, 9999 MMaayy 2233 1188::4411 ttttyyvv33 Many common uses of command substitution, however, are superseded by other mechanisms of zzsshh: %% llss --ll ``ttttyy`` ccrrww--rrww--rrww-- 11 rroooott 2200,, 2288 MMaayy 2233 1188::3355 //ddeevv//ttttyyqqcc %% llss --ll $$TTTTYY ccrrww--rrww--rrww-- 11 rroooott 2200,, 2288 MMaayy 2233 1188::3355 //ddeevv//ttttyyqqcc %% llss --ll ``wwhhiicchh rrnn`` --rrwwxxrr--xxrr--xx 11 rroooott 117722003322 MMaarr 66 1188::4400 //uussrr//pprriinncceettoonn//bbiinn//rrnn %% llss --ll ==rrnn --rrwwxxrr--xxrr--xx 11 rroooott 117722003322 MMaarr 66 1188::4400 //uussrr//pprriinncceettoonn//bbiinn//rrnn A command name with a == prepended is replaced with its full pathname. This can be very convenient. If it's not conve- nient for you, you can turn it off: -15- %% llss ==ffoooo ==bbaarr %% llss ==ffoooo ==bbaarr zzsshh:: ffoooo nnoott ffoouunndd %% sseettoopptt nnooeeqquuaallss %% llss ==ffoooo ==bbaarr ==ffoooo ==bbaarr Another nice feature is process substitution: %% wwhhoo || ffggrreepp --ff ==((pprriinntt --ll rroooott lleemmkkee sshhggcchhaann ssuubbbbaarraaoo)) rroooott ccoonnssoollee MMaayy 1199 1100::4411 lleemmkkee ttttyyqq00 MMaayy 2222 1100::0055 ((nnaarrnniiaa::00..00)) lleemmkkee ttttyyrr77 MMaayy 2222 1100::0055 ((nnaarrnniiaa::00..00)) lleemmkkee ttttyyrrdd MMaayy 2222 1100::0055 ((nnaarrnniiaa::00..00)) sshhggcchhaann ttttyyss11 MMaayy 2233 1166::5522 ((ggaauuddii..PPrriinncceettoonn..)) ssuubbbbaarraaoo ttttyytt77 MMaayy 2233 1155::0022 ((mmaadd5555ssxx1155..PPrriinnccee)) ssuubbbbaarraaoo ttttyyuu66 MMaayy 2233 1155::0044 ((mmaadd5555ssxx1155..PPrriinnccee)) sshhggcchhaann ttttyyvvbb MMaayy 2233 1166::5511 ((ggaauuddii..PPrriinncceettoonn..)) A command of the form ==((...)) is replaced with the name of a _f_i_l_e containing its output. (A command substitution, on the other hand, is replaced with the output itself.) pprriinntt --ll is like eecchhoo, excepts that it prints its arguments one per line, the way ffggrreepp expects them: %% pprriinntt --ll ffoooo bbaarr ffoooo bbaarr We could also have written: %% wwhhoo || ffggrreepp --ff ==((eecchhoo ''rroooott >> lleemmkkee >> sshhggcchhaann >> ssuubbbbaarraaoo'')) Using process substitution, you can edit the output of a command: %% eedd ==((wwhhoo || ffggrreepp --ff ~~//..ffrriieennddss)) 335555 gg//lleemmkkee//dd ww //ttmmpp//ffiillbbaarr 222266 qq %% ccaatt //ttmmpp//ffiillbbaarr rroooott ccoonnssoollee MMaayy 1199 1100::4411 sshhggcchhaann ttttyyss11 MMaayy 2233 1166::5522 ((ggaauuddii..PPrriinncceettoonn..)) ssuubbbbaarraaoo ttttyytt77 MMaayy 2233 1155::0022 ((mmaadd5555ssxx1155..PPrriinnccee)) ssuubbbbaarraaoo ttttyyuu66 MMaayy 2233 1155::0044 ((mmaadd5555ssxx1155..PPrriinnccee)) sshhggcchhaann ttttyyvvbb MMaayy 2233 1166::5511 ((ggaauuddii..PPrriinncceettoonn..)) -16- or easily read archived mail: %% mmaaiill --ff ==((zzccaatt ~~//mmaaiill//oollddzzsshhmmaaiill..ZZ)) ""//ttmmpp//zzsshhaa0066002244"":: 8844 mmeessssaaggeess,, 00 nneeww,, 4433 uunnrreeaadd >> 11 UU TTOO:: ppffaallssttaadd,, zzsshh ((1100)) 22 UU nnyyttiimm!!ttiimm@@uuuunneett..uuuu..nneett,, RRee:: ZZsshh oonn SSppaarrcc11 //SSuunnOOSS 44..00..33 33 UU JJAAMM%%TTPPNN@@uuttrrccggww..uuttcc..ccoomm,, zzsshh ffiixx ((1155)) 44 UU ddjjmm@@eenngg..uummdd..eedduu,, wwaayy ttoo ffiinndd oouutt iiff rruunnnniinngg zzsshh?? ((2255)) 55 UU ddjjmm@@eenngg..uummdd..eedduu,, RRee:: wwaayy ttoo ffiinndd oouutt iiff rruunnnniinngg zzsshh?? ((1177)) 66 rr ddjjmm@@eenngg..uummdd..eedduu,, MMeettaa .. ((1188)) 77 UU jjaacckk@@ccss..ggllaassggooww..aacc..uukk,, RRee:: pprroobblleemm bbuuiillddiinngg zzsshh ((114477)) 88 UU nnyyttiimm!!ttiimm@@uuuunneett..uuuu..nneett,, RRee:: ZZsshh oonn SSppaarrcc11 //SSuunnOOSS 44..00..33 99 uurrssaa!!jjmmdd,, AAnnootthheerr ffiixx...... ((6611)) 1100 UU ppppllaacceewwaa@@bbbbnn..ccoomm,, RRee:: vv1188ii008844:: ZZsshh 22..0000 -- AA ssmmaallll ccoommppllaaiinntt ((3366)) 1111 UU lluubbkkiinn@@ccss..rroocchheesstteerr..eedduu,, PPOOSSIIXX jjoobb ccoonnttrrooll ((3344)) 1122 UU yyaallee!!bbrroonnssoonn!!ttaann@@uuuunneett..UUUU..NNEETT 1133 UU bbrreetttt@@rrppii..eedduu,, zzsshh ((3366)) 1144 SS ssuubbbbaarraaoo,, zzsshh ssuucckkss!!!!!!!! ((228866)) 1155 UU ssnniibbrruu!!dd224411ss000088!!dd224411ss001133!!aallaa@@rreellaayy..EEUU..nneett,, zzsshh ((116655)) 1166 UU nnyyttiimm!!ttiimm@@uuuunneett..UUUU..NNEETT,, RRee:: ZZsshh oonn SSppaarrcc11 //SSuunnOOSS 44..00..33 1177 UU ssuubbbbaarraaoo,, zzsshh iiss aa jjuunnkk sshheellll ((4433)) 1188 UU aammaarraanntthh@@vveellaa..aaccss..ooaakkllaanndd..eedduu,, zzsshh ((3333)) 4433uu//8844 11:: xx %% llss --ll //ttmmpp//zzsshhaa0066002244 //ttmmpp//zzsshhaa0066002244 nnoott ffoouunndd Note that the shell creates a temporary file, and deletes it when the command is finished. %% ddiiffff ==((llss)) ==((llss --FF)) 33cc33 << ffoorrttuunnee ------ >> ffoorrttuunnee** 1100cc1100 << ssttrrffiillee ------ >> ssttrrffiillee** If you read zzsshh's man page, you may notice that <<((...)) is another form of process substitution which is similar to ==((...)). There is an important difference between the two. In the <<((...)) case, the shell creates a named pipe (FIFO) instead of a file. This is better, since it does not fill up the file system; but it does not work in all cases. In fact, if we had replaced ==((...)) with <<((...)) in the examples above, all of them would have stopped working except for ffggrreepp --ff <<((...)). You can not edit a pipe, or open it as a mail folder; ffggrreepp, however, has no problem with reading a list of words from a pipe. You may wonder why ddiiffff <<((ffoooo)) bbaarr doesn't work, since ffoooo || ddiiffff -- bbaarr works; this is because ddiiffff creates a temporary file if it notices that one of its arguments is --, and then copies its standard input to the temporary file. -17- >>((...)) is just like <<((...)) except that the command between the parentheses will get its input from the named pipe. %% ddvviippss --oo >>((llpprr)) zzsshh..ddvvii RReeddiirreeccttiioonn Apart from all the regular redirections like the Bourne shell has, zzsshh can do more. You can send the output of a command to more than one file, by specifying more redirec- tions like %% eecchhoo HHeelllloo WWoorrlldd >>ffiillee11 >>ffiillee22 and the text will end up in both files. Similarly, you can send the output to a file and into a pipe: %% mmaakkee >> mmaakkee..lloogg || ggrreepp EErrrroorr The same goes for input. You can make the input of a com- mand come from more than one file. %% ssoorrtt <> >>((...)). %% ffiinndd // --nnaammee ggaammeess 22>> >>((ggrreepp --vv ''PPeerrmmiissssiioonn'' >> rreeaalleerrrroorrss)) The above redirection will actually be implemented with a regular pipe, not a temporary named pipe. AAlliiaassiinngg Often-used commands can be abbreviated with an alias: %% aalliiaass uucc==uunnccoommpprreessss %% llss hhaannooii..ZZ %% uucc hhaannooii %% llss hhaannooii -18- or commands with certain desired options: %% aalliiaass ffmm==''ffiinnggeerr --mm'' %% ffmm rroooott LLooggiinn nnaammee:: rroooott IInn rreeaall lliiffee:: OOppeerraattoorr DDiirreeccttoorryy:: // SShheellll:: //bbiinn//ccsshh OOnn ssiinnccee MMaayy 1199 1100::4411::1155 oonn ccoonnssoollee 33 ddaayyss 55 hhoouurrss IIddllee TTiimmee NNoo uunnrreeaadd mmaaiill NNoo PPllaann.. %% aalliiaass lloocckk==''lloocckk --pp --6600000000'' %% lloocckk lloocckk:: //ddeevv//ttttyyrr44 oonn pphhooeenniixx.. ttiimmeeoouutt iinn 6600000000 mmiinnuutteess ttiimmee nnooww iiss FFrrii MMaayy 2244 0044::2233::1188 EEDDTT 11999911 KKeeyy:: %% aalliiaass ll==''llss --AAFF'' %% ll // ..bbaasshh__hhiissttoorryy kkaaddbb** ..bbaasshhrrcc lliibb@@ ..ccsshhrrcc lliicceennsseedd// ..eexxrrcc lloosstt++ffoouunndd// ..llooggiinn mmaaccssyymmaa ... Aliases can also be used to replace old commands: %% aalliiaass ggrreepp==eeggrreepp ppss==ssppss mmaakkee==ggmmaakkee %% aalliiaass wwhhooaammii==''eecchhoo rroooott'' %% wwhhooaammii rroooott or to define new ones: %% ccdd // %% aalliiaass sszz==''llss --ll || ssoorrtt --nn ++33 || ttaaiill --1100'' %% sszz ddrrwwxxrr--ssrr--xx 77 bbiinn 33007722 MMaayy 2233 1111::5599 eettcc ddrrwwxxrrwwxxrrwwxx 2266 rroooott 55112200 MMaayy 2244 0044::2200 ttmmpp ddrrwwxxrr--xxrr--xx 22 rroooott 88119922 DDeecc 2266 1199::3344 lloosstt++ffoouunndd ddrrwwxxrr--ssrr--xx 22 bbiinn 1144884488 MMaayy 2233 1188::4488 ddeevv --rr----rr----rr---- 11 rroooott 114400552200 DDeecc 2266 2200::0088 bboooott --rrwwxxrr--xxrr--xx 11 rroooott 331111117722 DDeecc 2266 2200::0088 kkaaddbb --rrwwxxrr--xxrr--xx 11 rroooott 11220099669955 AApprr 1166 1155::3333 vvmmuunniixx..oolldd --rrwwxxrr--xxrr--xx 11 rroooott 11220099770022 MMaayy 1144 1199::0044 vvmmuunniixx --rrwwxxrr--xxrr--xx 11 rroooott 11220099775588 MMaayy 2211 1122::2233 vvmmuunniixx..nneeww..kkeerrnneellmmaapp..oolldd --rrwwxxrr--xxrr--xx 11 rroooott 11771111884488 DDeecc 2266 2200::0088 vvmmuunniixx..oorrgg %% ccdd %% aalliiaass rraabbllee==''llss --AAFFttrrdd **((RR))'' nnrraabbllee==''llss --AAFFttrrdd **((^^RR))'' %% rraabbllee RREEAADDMMEE ffuunncc// bbiinn// ppuubb// NNeewwss// ssrrcc// nniicceeccoolloorrss eettcc// ssccrr// ttmmpp// iirriiss// zzsshh** %% nnrraabbllee MMaaiillbbooxxeess// mmaaiill// nnootteess -19- (The pattern **((RR)) matches all readable files in the current directory, and **((^^RR)) matches all unreadable files.) Most other shells have aliases of this kind (_c_o_m_m_a_n_d aliases). However, zzsshh also has _g_l_o_b_a_l aliases, which are substituted anywhere on a line. Global aliases can be used to abbreviate frequently-typed usernames, hostnames, etc. %% aalliiaass --gg mmee==ppffaallssttaadd gguunn==eeggssiirreerr mmjjmm==mmaarruucchhcckk %% wwhhoo || ggrreepp mmee ppffaallssttaadd ttttyypp00 MMaayy 2244 0033::3399 ((mmiicckkeeyy..PPrriinncceettoonn)) ppffaallssttaadd ttttyypp55 MMaayy 2244 0033::4422 ((mmiicckkeeyy..PPrriinncceettoonn)) %% ffmm gguunn LLooggiinn nnaammee:: eeggssiirreerr IInn rreeaall lliiffee:: EEmmiinn GGuunn SSiirreerr DDiirreeccttoorryy:: //uu//eeggssiirreerr SShheellll:: //bbiinn//sshh LLaasstt llooggiinn TThhuu MMaayy 2233 1199::0055 oonn ttttyyqq33 ffrroomm bbooww..PPrriinncceettoonn..EEDD NNeeww mmaaiill rreecceeiivveedd FFrrii MMaayy 2244 0022::3300::2288 11999911;; uunnrreeaadd ssiinnccee FFrrii MMaayy 2244 0022::3300::2277 11999911 %% aalliiaass --gg pphhxx==pphhooeenniixx..pprriinncceettoonn..eedduu wwaarrcc==wwuuaarrcchhiivvee..wwuussttll..eedduu %% ffttpp wwaarrcc CCoonnnneecctteedd ttoo wwuuaarrcchhiivvee..wwuussttll..eedduu.. Here are some more interesting uses. %% aalliiaass --gg MM==''|| mmoorree'' GGFF==''|| ffggrreepp --ff ~~//..ffrriieennddss'' %% wwhhoo MM ## _p_i_p_e_s _t_h_e _o_u_t_p_u_t _o_f wwhhoo _t_h_r_o_u_g_h mmoorree %% wwhhoo GGFF ## _s_e_e _i_f _y_o_u_r _f_r_i_e_n_d_s _a_r_e _o_n %% ww GGFF ## _s_e_e _w_h_a_t _y_o_u_r _f_r_i_e_n_d_s _a_r_e _d_o_i_n_g Another example makes use of zzsshh's process substitution. If you run NIS, and you miss being able to do this: %% ggrreepp ppffaallssttaadd //eettcc//ppaasssswwdd you can define an alias that will seem more natural than yyppmmaattcchh ppffaallssttaadd ppaasssswwdd: %% aalliiaass --gg PPAASSSS==''<<((yyppccaatt ppaasssswwdd))'' %% ggrreepp ppffaallssttaadd PPAASSSS ppffaallssttaadd::**::33556644::3355::PPaauull JJoohhnn FFaallssttaadd:://uu//ppffaallssttaadd:://uussrr//pprriinncceettoonn//bbiinn//zzsshh If you're really crazy, you can even call it //eettcc//ppaasssswwdd: %% aalliiaass --gg //eettcc//ppaasssswwdd==''<<((yyppccaatt ppaasssswwdd))'' %% ggrreepp ppffaallssttaadd //eettcc//ppaasssswwdd ppffaallssttaadd::**::33556644::3355::PPaauull JJoohhnn FFaallssttaadd:://uu//ppffaallssttaadd:://uussrr//pprriinncceettoonn//bbiinn//zzsshh The last example shows one of the perils of global aliases; they have a lot of potential to cause confusion. For exam- ple, if you defined a global alias called || (which is possi- ble), zzsshh would begin to act very strangely; every pipe sym- bol would be replaced with the text of your alias. To some extent, global aliases are like macros in C; discretion is advised in using them and in choosing names for them. Using -20- names in all caps is not a bad idea, especially for aliases which introduce shell metasyntax (like MM and GGFF above). Note that zzsshh aliases are not like csh aliases. The syntax for defining them is different, and they do not have argu- ments. All your favorite csh aliases will probably not work under zzsshh. For example, if you try: aalliiaass rrmm mmvv ''\\!!** //ttmmpp//wwaasstteebbaasskkeett'' no aliases will be defined, but zzsshh will not report an error. In csh, this line defines an alias that makes rrmm safe---files that are rrmm'd will be moved to a temporary directory instead of instantly destroyed. In zzsshh's syntax, however, this line asks the shell to print any existing alias definitions for rrmm, mmvv, or !!** //ttmmpp//wwaasstteebbaasskkeett. Since there are none, most likely, the shell will not print any- thing, although aalliiaass will return a nonzero exit code. The proper syntax is this: aalliiaass rrmm==''mmvv \\!!** //ttmmpp//wwaasstteebbaasskkeett'' However, this won't work either: %% rrmm ffoooo..ddvvii zzsshh:: nnoo mmaattcchheess ffoouunndd:: !!** While this makes rrmm safe, it is certainly not what the user intended. In zzsshh, you must use a shell function for this: %% uunnaalliiaass rrmm %% rrmm (()) {{ mmvv $$** //ttmmpp//wwaasstteebbaasskkeett }} %% rrmm ffoooo..ddvvii %% llss //ttmmpp//wwaasstteebbaasskkeett ffoooo..ddvvii While this is much cleaner and easier to read (I hope you will agree), it is not csh-compatible. Therefore, a script to convert csh aliases and variables has been provided. You should only need to use it once, to convert all your csh aliases and parameters to zzsshh format: %% ccsshh ccsshh>> aalliiaass ll llss --AAFF mmoorree lleessss oonn llaasstt --22 !!::11 ;; wwhhoo || ggrreepp !!::11 ccsshh>> eexxiitt %% cc22zz >>nneeaatt__zzsshh__aalliiaasseess %% ccaatt nneeaatt__zzsshh__aalliiaasseess aalliiaass ll==''llss --AAFF'' aalliiaass mmoorree==''lleessss'' oonn (()) {{ llaasstt --22 $$11 ;; wwhhoo || ggrreepp $$11 }} ...... -21- The first two aliases were converted to regular zzsshh aliases, while the third, since it needed to handle arguments, was converted to a function. cc22zz can convert most aliases to zzsshh format without any problems. However, if you're using some really arcane csh tricks, or if you have an alias with a name like ddoo (which is reserved in zzsshh), you may have to fix some of the aliases by hand. The cc22zz script checks your csh setup, and produces a list of zzsshh commands which replicate your aliases and parameter set- tings as closely as possible. You could include its output in your startup file, ..zzsshhrrcc. HHiissttoorryy There are several ways to manipulate history in zzsshh. One way is to use csh-style !! history: %% //uussrr//llooccaall//bbiinn//!!::00 !!--22**::ss//ffoooo//bbaarr// >>>>!!$$ If you don't want to use this, you can turn it off by typing sseettoopptt nnoobbaanngghhiisstt. If you are afraid of accidentally exe- cuting the wrong command you can set the _H_I_S_T_V_E_R_I_F_Y option. If this option is set, commands that result from history expansion will not be executed immediately, but will be put back into the editor buffer for further consideration. If you're not familiar with !! history, here follows some explanation. History substitutions always start with a !!, commonly called "bang". After the !! comes an (optional) designation of which "event" (command) to use, then a colon, and then a designation of what word of that command to use. For example, !!--_n refers to the command _n commands ago. %% llss ffoooo bbaarr %% ccdd ffoooo %% !!--22 llss bbaazz bbaamm No word designator was used, which means that the whole com- mand referred to was repeated. Note that the shell will echo the result of the history substitution. The word des- ignator can, among other things, be a number indicating the argument to use, where 00 is the command. %% //uussrr//bbiinn//llss ffoooo ffoooo %% !!::00 bbaarr //uussrr//bbiinn//llss bbaarr bbaarr In this example, no event designator was used, which tells -22- zzsshh to use the previous command. A $$ specifies the last argument %% mmkkddiirr //uussrr//llooccaall//lliibb//eemmaaccss//ssiittee--lliisspp//ccaallcc %% ccdd !!::$$ ccdd //uussrr//llooccaall//lliibb//eemmaaccss//ssiittee--lliisspp//ccaallcc If you use more words of the same command, only the first !! needs an event designator. %% mmaakkee pprriigg >>>> mmaakkee..lloogg mmaakkee:: ****** NNoo rruullee ttoo mmaakkee ttaarrggeett ``pprriigg''.. SSttoopp.. %% ccdd ssrrcc %% !!--22::00 pprroogg >>>> !!::$$ mmaakkee pprroogg >>>> mmaakkee..lloogg This is different from csh, where a bang with no event des- ignator always refers to the previous command. If you actu- ally like this behaviour, set the _C_S_H_J_U_N_K_I_E_H_I_S_T_O_R_Y option. %% sseettoopptt ccsshhjjuunnkkiieehhiissttoorryy %% !!--22::00 pprroogg22 >>>> !!::$$ mmaakkee pprroogg22 >>>> ccsshhjjuunnkkiieehhiissttoorryy Another way to use history is to use the ffcc command. For example, if you type an erroneous command: %% ffoorr ii iinn ``ccaatt //eettcc//cclliieennttss`` ddoo rrppuu $$ii ddoonnee zzsshh:: ccoommmmaanndd nnoott ffoouunndd:: rrppuu zzsshh:: ccoommmmaanndd nnoott ffoouunndd:: rrppuu zzsshh:: ccoommmmaanndd nnoott ffoouunndd:: rrppuu ... typing ffcc will execute an editor on this command, allowing you to fix it. (The default editor is vvii, by the way, not eedd). %% ffcc 4499 //rrppuu//ss////rruupp//pp rruupp $$ii ww 4499 qq ffoorr ii iinn ``ccaatt //eettcc//cclliieennttss`` ddoo rruupp $$ii ddoonnee bbeeaamm uupp 22 ddaayyss,, 1100::1177,, llooaadd aavveerraaggee:: 00..8866,, 00..8800,, 00..5500 bbooww uupp 44 ddaayyss,, 88::4411,, llooaadd aavveerraaggee:: 00..9911,, 00..8800,, 00..5500 bbuurrnn uupp 1177::1188,, llooaadd aavveerraaggee:: 00..9911,, 00..8800,, 00..5500 -23- bbuurrsstt uupp 99 ddaayyss,, 11::4499,, llooaadd aavveerraaggee:: 00..9955,, 00..8800,, 00..5500 ttaann uupp 1111::1144,, llooaadd aavveerraaggee:: 00..9911,, 00..8800,, 00..5500 bbaatthhee uupp 33 ddaayyss,, 1177::4499,, llooaadd aavveerraaggee:: 11..8844,, 11..7799,, 11..5500 bbiirrdd uupp 11 ddaayy,, 99::1133,, llooaadd aavveerraaggee:: 11..9955,, 11..8822,, 11..5511 bboonnnneett uupp 22 ddaayyss,, 2211::1188,, llooaadd aavveerraaggee:: 00..9933,, 00..8800,, 00..5500 ... A variant of the ffcc command is rr, which redoes the last com- mand, with optional changes: %% eecchhoo ffoooo ffoooo %% rr eecchhoo ffoooo ffoooo %% eecchhoo ffoooo ffoooo %% rr ffoooo==bbaarr eecchhoo bbaarr bbaarr CCoommmmaanndd LLiinnee EEddiittiinngg zzsshh's command line editor, ZZLLEE, is quite powerful. It is designed to emulate either emacs or vi; the default is emacs. To set the bindings for vi mode, type bbiinnddkkeeyy --vv. If your EEDDIITTOORR or VVIISSUUAALL environment variable is vi, zzsshh will use vi emulation by default. You can then switch to emacs mode with bbiinnddkkeeyy --ee. In addition to basic editing, the shell allows you to recall previous lines in the history. In emacs mode, this is done with _^_P (control-P) or (on many terminals) with the cursor- up key: %% llss ~~ -- RREEAADDMMEE ffiillee mmaaiill ppuubb ttmmpp MMaaiillbbooxxeess bbiinn ffuunncc nniicceeccoolloorrss ssccrr zzsshh NNeewwss eettcc iirriiss nnootteess ssrrcc %% eecchhoo ffoooobbaarr ffoooobbaarr %% _^_P %% eecchhoo ffoooobbaarr_^_P %% llss ~~__ Pressing _^_P once brings up the previous line (eecchhoo ffoooobbaarr); pressing it again brings up the line before that (llss ~~). The cursor is left at the end of the line, allowing you to edit the line if desired before executing it. In many cases, ZZLLEE eliminates the need for the ffcc command, since it is powerful enough to handle even multiline commands: -24- %% ffoorr ii iinn aa bb cc dd ee >> ddoo >> eecchhoo $$ii >> ddoonnee aa bb cc dd ee %% _^_P %% ffoorr ii iinn aa bb cc dd ee ddoo eecchhoo $$ii ddoonnee__ Now you can just move up to the part you want to change... %% ffoorr ii iinn aa__ bb cc dd ee ddoo eecchhoo $$ii ddoonnee change it, and execute the new command. %% ffoorr ii iinn ff gg hh ii jj ddoo eecchhoo $$ii ddoonnee ff gg hh ii jj Also, you can search the history for a certain command using _E_S_C_-_P, this will look for the last command that started with the (part of the) word at the beginning of the current line. Hitting _E_S_C_-_P another time gets you the command before that, etc. %% sseett _E_S_C_-_P %% sseettoopptt aauuttoolliisstt _E_S_C_-_P %% sseettoopptt nnooccoorrrreecctt__ Another way is to do an incremental search, emacs-style: %% _^_R %% __ ii--sseeaarrcchh:: %% llss__ //uussrr//bbiinn ii--sseeaarrcchh:: ll %% ddaattee >> ffooooffiillee..__cc -25- ii--sseeaarrcchh:: llee Suppose you have retrieved an old history event in one of these ways and would like to execute several consecutive old commands starting with this one. ^^OO will execute the cur- rent command and then put the next command from the history into the editor buffer. Typing ^^OO several times will there- fore reexecute several consecutive commands from the his- tory. Of course, you can edit some of those commands in between. In addition to completion (see below), _T_A_B performs expan- sion if possible. %% llss **..cc_T_A_B %% llss ffooooffiillee..cc ffoorrttuunnee..cc rrnndd..cc ssttrrffiillee..cc uunnssttrr..cc__ For example, suppose you have a bunch of weird files in an important directory: %% llss ** ** ** ;; && %% $$????ffoooo ddssppffookk ffoooo..cc !!""ffoooo""!! `` \\ `` ffoooo rrrrrr You want to remove them, but you don't want to damage ffoooo..cc. Here is one way to do this: %% rrmm **_T_A_B %% rrmm \\ \\ \\**\\ \\**\\ \\**\\ \\ \\ \\!!\\""ffoooo\\""\\!! \\;;\\ \\&&\\ %%\\ \\$$'' ''''ffoooo \\``\\ \\\\\\ \\`` ddssppffookk ffoooo ffoooo..cc rrrrrr__ When you expand **, zzsshh inserts the names of all the files into the editing buffer, with proper shell quoting. Now, just move back and remove ffoooo..cc from the buffer: %% rrmm \\ \\ \\**\\ \\**\\ \\**\\ \\ \\ \\!!\\""ffoooo\\""\\!! \\;;\\ \\&&\\ %%\\ \\$$'' ''''ffoooo \\``\\ \\\\\\ \\`` ddssppffookk ffoooo rr__rrrr and press return. Everything except ffoooo..cc will be deleted from the directory. If you do not want to actually expand the current word, but would like to see what the matches are, type ^^XXgg. %% rrmm ff**_^_X_g ffoooo ffoooo..cc %% rrmm ff**__ Here's another trick; let's say you have typed this command in: %% ggcccc --oo xx..oouutt ffoooobb..cc --gg --WWppooiinntteerr--aarriitthh --WWttrriiggrraapphhss__ and you forget which library you want. You need to escape out for a minute and check by typing llss //uussrr//lliibb, or some -26- other such command; but you don't want to retype the whole command again, and you can't press return now because the current command is incomplete. In zzsshh, you can put the line on the _b_u_f_f_e_r _s_t_a_c_k, using _E_S_C_-_Q, and type some other com- mands. The next time a prompt is printed, the ggcccc line will be popped off the stack and put in the editing buffer auto- matically; you can then enter the proper library name and press return (or, _E_S_C_-_Q again and look for some other libraries whose names you forgot). A similar situation: what if you forget the option to gcc that finds bugs using AI techniques? You could either use _E_S_C_-_Q again, and type mmaann ggcccc, or you could press _E_S_C_-_H, which essentially does the same thing; it puts the current line on the buffer stack, and executes the command rruunn--hheellpp ggcccc, where rruunn--hheellpp is an alias for mmaann. Another interesting command is _E_S_C_-_A. This executes the current line, but retains it in the buffer, so that it appears again when the next prompt is printed. Also, the cursor stays in the same place. This is useful for execut- ing a series of similar commands: %% cccc ggrrookk..cc --gg --llcc --llggll --llssuunn --llmmaalllloocc --BBssttaattiicc --oo bb..oouutt %% cccc ffuubbaarr..cc --gg --llcc --llggll --llssuunn --llmmaalllloocc --BBssttaattiicc --oo bb..oouutt %% cccc ffoooobbllee..cc --gg --llcc --llggll --llssuunn --llmmaalllloocc --BBssttaattiicc --oo bb..oouutt The _E_S_C_-_' command is useful for managing the shell's quoting conventions. Let's say you want to print this string: ddoonn''tt ddoo tthhaatt;; ttyyppee ''rrmm --rrff \\**'',, wwiitthh aa \\ bbeeffoorree tthhee **.. All that is necessary is to type it into the editing buffer: %% ddoonn''tt ddoo tthhaatt;; ttyyppee ''rrmm --rrff \\**'',, wwiitthh aa \\ bbeeffoorree tthhee **.. press _E_S_C_-_' (escape-quote): %% ''ddoonn''\\''''tt ddoo tthhaatt;; ttyyppee ''\\''''rrmm --rrff \\**''\\'''',, wwiitthh aa \\ bbeeffoorree tthhee **..'' then move to the beginning and add the eecchhoo command. %% eecchhoo ''ddoonn''\\''''tt ddoo tthhaatt;; ttyyppee ''\\''''rrmm --rrff \\**''\\'''',, wwiitthh aa \\ bbeeffoorree tthhee **..'' ddoonn''tt ddoo tthhaatt;; ttyyppee ''rrmm --rrff \\**'',, wwiitthh aa \\ bbeeffoorree tthhee **.. Let's say you want to create an alias to do this eecchhoo com- mand. This can be done by recalling the line with _^_P and pressing _E_S_C_-_' again: %% ''eecchhoo ''\\''''ddoonn''\\''''\\''\\''''''\\''''tt ddoo tthhaatt;; ttyyppee ''\\''''\\''\\''''''\\''''rrmm --rrff \\**''\\''''\\''\\''''''\\'''',, wwiitthh aa \\ bbeeffoorree tthhee **..''\\'''''' and then move to the beginning and add the command to create -27- an alias. %% aalliiaass zzooooff==''eecchhoo ''\\''''ddoonn''\\''''\\''\\''''''\\''''tt ddoo tthhaatt;; ttyyppee ''\\''''\\''\\''''''\\''''rrmm --rrff \\**''\\''''\\''\\''''''\\'''',, wwiitthh aa \\ bbeeffoorree tthhee **..''\\'''''' %% zzooooff ddoonn''tt ddoo tthhaatt;; ttyyppee ''rrmm --rrff \\**'',, wwiitthh aa \\ bbeeffoorree tthhee **.. If one of these fancy editor commands changes your command line in a way you did not intend, you can undo changes with ^^__, if you can get it out of your keyboard, or ^^XX^^UU, other- wise. Another use of the editor is to edit the value of variables. For example, an easy way to change your path is to use the vvaarreedd command: %% vvaarreedd PPAATTHH >> //uu//ppffaallssttaadd//ssccrr:://uu//ppffaallssttaadd//bbiinn//ssuunn44:://uu//mmaarruucchhcckk//ssccrr:://uu//ssuubbbbaarraaoo//bbiinn:://uu//mmaarruucc hhcckk//bbiinn:://uu//ssuubbbbaarraaoo//ssccrriippttss:://uussrr//pprriinncceettoonn//bbiinn:://uussrr//uuccbb:://uussrr//bbiinn:://bbiinn:://uussrr//hhoosstt ss:://uussrr//pprriinncceettoonn//bbiinn//XX1111:://..//uussrr//llaanngg:://..//uussrr//eettcc:://..//eettcc You can now edit the path. When you press return, the con- tents of the edit buffer will be assigned to PPAATTHH. CCoommpplleettiioonn Another great zzsshh feature is completion. If you hit _T_A_B, zzsshh will complete all kinds of stuff. Like commands or filenames: %% ccoommpp_T_A_B %% ccoommpprreessss __ %% llss nniicc_T_A_B %% llss nniicceeccoolloorrss __ %% llss //uussrr//pprr_T_A_B %% llss //uussrr//pprriinncceettoonn//__ %% llss --ll ==ccoomm_T_A_B %% llss --ll ==ccoommpprreessss __ If the completion is ambiguous, the editor will beep. If you find this annoying, you can set the _N_O_L_I_S_T_B_E_E_P option. Completion can even be done in the middle of words. To use this, you will have to set the _C_O_M_P_L_E_T_E_I_N_W_O_R_D option: %% sseettoopptt ccoommpplleetteeiinnwwoorrdd %% llss //uussrr//pptt__oonn_T_A_B %% llss //uussrr//pprriinncceett__oonn// %% sseettoopptt aallwwaayyssttooeenndd %% llss //uussrr//pptt__oonn_T_A_B %% llss //uussrr//pprriinncceettoonn//__ -28- You can list possible completions by pressing _^_D: %% llss //vvmmuu_T_A_B _-_-_b_e_e_p_-_- %% llss //vvmmuunniixx__ %% llss //vvmmuunniixx_^_D vvmmuunniixx vvmmuunniixx..oolldd vvmmuunniixx..nneeww..kkeerrnneellmmaapp..oolldd vvmmuunniixx..oorrgg Or, you could just set the _A_U_T_O_L_I_S_T option: %% sseettoopptt aauuttoolliisstt %% llss //vvmmuu_T_A_B _-_-_b_e_e_p_-_- vvmmuunniixx vvmmuunniixx..oolldd vvmmuunniixx..nneeww..kkeerrnneellmmaapp..oolldd vvmmuunniixx..oorrgg %% llss //vvmmuunniixx__ If you like to see the types of the files in these lists, like in llss --FF, you can set the _L_I_S_T_T_Y_P_E_S option. Together with _A_U_T_O_L_I_S_T you can use _L_I_S_T_A_M_B_I_G_U_O_U_S. This will only list the possibilities if there is no unambiguous part to add: %% sseettoopptt lliissttaammbbiigguuoouuss %% llss //vvmmuu_T_A_B _-_-_b_e_e_p_-_- %% llss //vvmmuunniixx___T_A_B _-_-_b_e_e_p_-_- vvmmuunniixx vvmmuunniixx..oolldd vvmmuunniixx..nneeww..kkeerrnneellmmaapp..oolldd vvmmuunniixx..oorrgg If you don't want several of these listings to scroll the screen so much, the _A_L_W_A_Y_S_L_A_S_T_P_R_O_M_P_T option is useful. If set, you can continue to edit the line you were editing, with the completion listing appearing beneath it. Another interesting option is _M_E_N_U_C_O_M_P_L_E_T_E. This affects the way _T_A_B works. Let's look at the //vvmmuunniixx example again: %% sseettoopptt mmeennuuccoommpplleettee %% llss //vvmmuu_T_A_B %% llss //vvmmuunniixx_T_A_B %% llss //vvmmuunniixx..nneeww..kkeerrnneellmmaapp..oolldd_T_A_B %% llss //vvmmuunniixx..oolldd__ Each time you press _T_A_B, it displays the next possible com- pletion. In this way, you can cycle through the possible completions until you find the one you want. The _A_U_T_O_M_E_N_U option makes a nice compromise between this method of completion and the regular method. If you set this option, pressing _T_A_B once completes the unambiguous part normally, pressing the _T_A_B key repeatedly after an ambiguous completion will cycle through the possible comple- tions. -29- Another option you could set is _R_E_C_E_X_A_C_T, which causes exact matches to be accepted, even if there are other possible completions: %% sseettoopptt rreecceexxaacctt %% llss //vvmmuu_T_A_B _-_-_b_e_e_p_-_- vvmmuunniixx vvmmuunniixx..oolldd vvmmuunniixx..nneeww..kkeerrnneellmmaapp..oolldd vvmmuunniixx..oorrgg %% llss //vvmmuunniixx___T_A_B %% llss //vvmmuunniixx __ To facilitate the typing of pathnames, a slash will be added whenever a directory is completed. Some computers don't like the spurious slashes at the end of directory names. In that case, the _A_U_T_O_R_E_M_O_V_E_S_L_A_S_H option comes to rescue. It will remove these slashes when you type a space or return after them. The _f_i_g_n_o_r_e variable lists suffixes of files to ignore dur- ing completion. %% llss ffoooo_T_A_B _-_-_b_e_e_p_-_- ffooooffiillee..cc ffooooffiillee..oo %% ffiiggnnoorree==(( ..oo \\~~ ..bbaakk ..jjuunnkk )) %% llss ffoooo_T_A_B %% llss ffooooffiillee..cc __ Since ffooooffiillee..oo has a suffix that is in the ffiiggnnoorree list, it was not considered a possible completion of ffoooo. Username completion is also supported: %% llss ~~ppffaall_T_A_B %% llss ~~ppffaallssttaadd//__ and parameter name completion: %% eecchhoo $$OORRGG_T_A_B %% eecchhoo $$OORRGGAANNIIZZAATTIIOONN __ %% eecchhoo $${{OORRGG_T_A_B %% eecchhoo $${{OORRGGAANNIIZZAATTIIOONN __ Note that in the last example a space is added after the completion as usual. But if you want to add a colon or closing brace, you probably don't want this extra space. Setting the _A_U_T_O_P_A_R_A_M_K_E_Y_S option will automatically remove this space if you type a colon or closing brace after such a completion. There is also option completion: %% sseettoopptt nnooccll_T_A_B %% sseettoopptt nnoocclloobbbbeerr __ -30- and binding completion: %% bbiinnddkkeeyy ''^^XX^^XX'' ppuu_T_A_B %% bbiinnddkkeeyy ''^^XX^^XX'' ppuusshh--lliinnee __ The ccoommppccttll command is used to control completion of the arguments of specific commands. For example, to specify that certain commands take other commands as arguments, you use ccoommppccttll --cc: %% ccoommppccttll --cc mmaann nnoohhuupp %% mmaann uupptt_T_A_B %% mmaann uuppttiimmee __ To specify that a command should complete filenames, you should use ccoommppccttll --ff. This is the default. It can be com- bined with --cc, as well. %% ccoommppccttll --ccff eecchhoo %% eecchhoo uupptt_T_A_B %% eecchhoo uuppttiimmee __ %% eecchhoo ffoo_T_A_B %% eecchhoo ffoooo..cc Similarly, use --oo to specify options, --vv to specify vari- ables, and --bb to specify bindings. %% ccoommppccttll --oo sseettoopptt uunnsseettoopptt %% ccoommppccttll --vv ttyyppeesseett vvaarreedd uunnsseett eexxppoorrtt %% ccoommppccttll --bb bbiinnddkkeeyy You can also use --kk to specify a custom list of keywords to use in completion. After the --kk comes either the name of an array or a literal array to take completions from. %% ffttpphhoossttss==((ffttpp..uuuu..nneett wwuuaarrcchhiivvee..wwuussttll..eedduu)) %% ccoommppccttll --kk ffttpphhoossttss ffttpp %% ffttpp wwuu_T_A_B %% ffttpp wwuuaarrcchhiivvee..wwuussttll..eedduu __ %% ccoommppccttll --kk ''((ccppiirraazzzzii ssuubbbbaarraaoo ssuukktthhnnkkrr))'' mmaaiill ffiinnggeerr %% ffiinnggeerr ccpp_T_A_B %% ffiinnggeerr ccppiirraazzzzii __ To better specify the files to complete for a command, use the --gg option which takes any glob pattern as an argument. Be sure to quote the glob patterns as otherwise they will be expanded when the ccoommppccttll command is run. %% llss lleetttteerr..tteexx lleetttteerr..ddvvii lleetttteerr..aauuxx lleetttteerr..lloogg lleetttteerr..ttoocc %% ccoommppccttll --gg ''**..tteexx'' llaatteexx %% ccoommppccttll --gg ''**..ddvvii'' xxddvvii ddvviippss -31- %% llaatteexx ll_T_A_B %% llaatteexx lleetttteerr..tteexx __ %% xxddvvii ll_T_A_B %% xxddvvii lleetttteerr..ddvvii __ Glob patterns can include qualifiers within parentheses. To rmdir only directories and cd to directories and symbolic links pointing to them: %% ccoommppccttll --gg ''**((--//))'' ccdd %% ccoommppccttll --gg ''**((//))'' rrmmddiirr RCS users like to run commands on files which are not in the current directory, but in the RCS subdirectory where they all get ,,vv suffixes. They might like to use %% ccoommppccttll --gg ''RRCCSS//**((::tt::ss//\\,,vv////))'' ccoo rrlloogg rrccss %% llss RRCCSS bbuuiillttiinn..cc,,vv lleexx..cc,,vv zzllee__mmaaiinn..cc,,vv %% rrlloogg bbuu_T_A_B %% rrlloogg bbuuiillttiinn..cc __ The ::tt modifier keeps only the last part of the pathname and the ::ss//\\,,vv//// will replace any ,,vv by nothing. The --ss flag is similar to --gg, but it uses all expansions, instead of just globbing, like brace expansion, parameter substitution and command substitution. %% ccoommppccttll --ss ''$$((sseettoopptt))'' uunnsseettoopptt will only complete options which are actually set to be arguments to uunnsseettoopptt. Sometimes a command takes another command as its argument. You can tell zzsshh to complete commands as the first argument to such a command and then use the completion method of the second command. The --ll flag with a null-string argument is used for this. %% ccoommppccttll --ll '''' nnoohhuupp eexxeecc %% nnoohhuupp ccoommpp_T_A_B %% nnoohhuupp ccoommpprreessss __ %% nnoohhuupp ccoommpprreessss ffiill_T_A_B %% nnoohhuupp ccoommpprreessss ffiilleennaammee __ Sometimes you would like to run really complicated commands to find out what the possible completions are. To do this, you can specify a shell function to be called that will assign the possible completions to a variable called reply. Note that this variable must be an array. Here's another (much slower) way to get the completions for ccoo and friends: %% ffuunnccttiioonn ggeettrrccss {{ -32- >> rreeppllyy==(()) >> ffoorr ii iinn RRCCSS//** >> ddoo >> rreeppllyy==(($$rreeppllyy[[**]] $$((bbaasseennaammee $$ii ,,vv)))) >> ddoonnee >> }} %% ccoommppccttll --KK ggeettrrccss ccoo rrlloogg rrccss Some command arguments use a prefix that is not a part of the things to complete. The kill builtin command takes a signal name after a --. To make such a prefix be ignored in the completion process, you can use the --PP flag. %% ccoommppccttll --PP -- --kk ssiiggnnaallss kkiillll %% kkiillll --HH_T_A_B %% kkiillll --HHUUPP __ TeX is usually run on files ending in ..tteexx, but also some- times on other files. It is somewhat annoying to specify that the arguments of TeX should end in ..tteexx and then not be able to complete these other files. Therefore you can spec- ify things like "Complete to files ending in ..tteexx if avail- able, otherwise complete to any filename.". This is done with _x_o_red completion: %% ccoommppccttll --gg ''**..tteexx'' ++ --ff tteexx The ++ tells the editor to only take the next thing into account if the current one doesn't generate any matches. If you have not changed the default completion, the above exam- ple is in fact equivalent to %% ccoommppccttll --gg ''**..tteexx'' ++ tteexx as a lone ++ at the end is equivalent to specifying the default completion after the ++. This form of completion is also frequently used if you want to run some command only on a certain type of files, but not necessarily in the current directory. In this case you will want to complete both files of this type and directories. Depending on your pref- erences you can use either of %% ccoommppccttll --gg ''**..ppss'' ++ --gg ''**((--//))'' gghhoossttvviieeww %% ccoommppccttll --gg ''**..ppss **((--//))'' gghhoossttvviieeww where the first one will only complete directories (and sym- bolic links pointing to directories) if no postscript file matches the already typed part of the argument. EExxtteennddeedd ccoommpplleettiioonn If you play with completion, you will soon notice that you would like to specify what to complete, depending on what flags you give to the command and where you are on the -33- command line. For example, a command could take any file- name argument after a --ff flag, a username after a --uu flag and an executable after a --xx flag. This section will intro- duce you to the ways to specify these things. To many peo- ple it seems rather difficult at first, but taking the trou- ble to understand it can save you lots of typing in the end. Even I keep being surprised when zzsshh manages to complete a small or even empty prefix to the right file in a large directory. To tell zzsshh about these kinds of completion, you use "extended completion" by specifying the --xx flag to compctl. The --xx flag takes a list of patterns/flags pairs. The pat- terns specify when to complete and the flags specify what. The flags are simply those mentioned above, like --ff or --gg _g_l_o_b _p_a_t_t_e_r_n. As an example, the rr[[_s_t_r_i_n_g_1,,_s_t_r_i_n_g_2]] pattern matches if the cursor is after something that starts with _s_t_r_i_n_g_1 and before something that starts with _s_t_r_i_n_g_2. The _s_t_r_i_n_g_2 is often something that you do not want to match anything at all. %% llss ffoooo11 bbaarr11 ffoooo..ZZ bbaarr..ZZ %% ccoommppccttll --gg ''^^**..ZZ'' --xx ''rr[[--dd,,------]]'' --gg ''**..ZZ'' ---- ccoommpprreessss %% ccoommpprreessss ff_T_A_B %% ccoommpprreessss ffoooo11 __ %% ccoommpprreessss --dd ff_T_A_B %% ccoommpprreessss --dd ffoooo..ZZ __ In the above example, if the cursor is after the --dd the pat- tern will match and therefore zzsshh uses the --gg **..ZZ flag that will only complete files ending in ..ZZ. Otherwise, if no pattern matches, it will use the flags before the --xx and in this case complete every file that does not end in ..ZZ. The ss[[_s_t_r_i_n_g]] pattern matches if the current word starts with _s_t_r_i_n_g. The _s_t_r_i_n_g itself is not considered to be part of the completion. %% ccoommppccttll --xx ''ss[[--]]'' --kk ssiiggnnaallss ---- kkiillll %% kkiillll --HH_T_A_B %% kkiillll --HHUUPP __ The ttaarr command takes a tar file as an argument after the --ff option. The cc[[_o_f_f_s_e_t,,_s_t_r_i_n_g]] pattern matches if the word in position _o_f_f_s_e_t relative to the current word is _s_t_r_i_n_g. More in particular, if _o_f_f_s_e_t is -1, it matches if the pre- vious word is _s_t_r_i_n_g. This suggests %% ccoommppccttll --ff --xx ''cc[[--11,,--ff]]'' --gg ''**..ttaarr'' ---- ttaarr But this is not enough. The --ff option could be the last of -34- a longer string of options. CC[[...,,...]] is just like cc[[...,,...]], except that it uses glob-like pattern matching for _s_t_r_i_n_g. So %% ccoommppccttll --ff --xx ''CC[[--11,,--**ff]]'' --gg ''**..ttaarr'' ---- ttaarr will complete tar files after any option string ending in an ff. But we'd like even more. Old versions of tar used all options as the first argument, but without the minus sign. This might be inconsistent with option usage in all other commands, but it is still supported by newer versions of ttaarr. So we would also like to complete tar files if the first argument ends in an ff and we're right behind it. We can `and' patterns by putting them next to each other with a space between them. We can `or' these sets by putting comma's between them. We will also need some new patterns. pp[[_n_u_m]] will match if the current argument (the one to be completed) is the _n_u_mth argument. WW[[_i_n_d_e_x,,_p_a_t_t_e_r_n]] will match if the argument in place _i_n_d_e_x matches the _p_a_t_t_e_r_n. This gives us %% ccoommppccttll --ff --xx ''CC[[--11,,--**ff]] ,, WW[[11,,**ff]] pp[[22]]'' --gg ''**..ttaarr'' ---- ttaarr In words: If the previous argument is an option string that ends in an ff, or the first argument ended in an ff and it is now the second argument, then complete only filenames ending in ..ttaarr. All the above examples used only one set of patterns with one completion flag. You can use several of these pat- tern/flag pairs separated by a --. The first matching pat- tern will be used. Suppose you have a version of ttaarr that supports compressed files by using a --ZZ option. Leaving the old tar syntax aside for a moment, we would like to complete files ending in ..ttaarr..ZZ if a --ZZ option has been used and files ending in ..ttaarr otherwise, all this only after a --ff flag. Again, the --ZZ can be alone or it can be part of a longer option string, perhaps the same as that of the --ff flag. Here's how to do it; note the backslash and the sec- ondary prompt which are not part of the ccoommppccttll command. %% ccoommppccttll --ff --xx ''CC[[--11,,--**ZZ**ff]] ,, RR[[--**ZZ**,,------]] CC[[--11,,--**ff]]'' --gg ''**..ttaarr..ZZ'' -- \\ >> ''CC[[--11,,--**ff]]'' --gg ''**..ttaarr'' ---- ttaarr The first pattern set tells us to match if either the previ- ous argument was an option string including a ZZ and ending in an ff or there was an option string with a ZZ somewhere and the previous word was any option string ending in an ff. If this is the case, we need a compressed tar file. Only if this is not the case the second pattern set will be consid- ered. By the way, RR[[_p_a_t_t_e_r_n_1,,_p_a_t_t_e_r_n_2]] is just like rr[[...,,...]] except that it uses pattern matching with shell metacharacters instead of just strings. -35- You will have noticed the ---- before the command name. This ends the list of pattern/flag pairs of --xx. It is usually used just before the command name, but you can also use an extended completion as one part of a list of xored comple- tions, in which case the ---- appears just before one of the ++ signs. Note the difference between using extended completion as part of a list of xored completions as in %% llss ffoooo bbaarr %% ccoommppccttll --xx ''rr[[--dd,,------]]'' --gg ''**..ZZ'' ---- ++ --gg ''^^**..ZZ'' ccoommpprreessss %% ccoommpprreessss --dd ff_T_A_B %% ccoommpprreessss --dd ffoooo __ and specifying something before the --xx as in %% ccoommppccttll --gg ''^^**..ZZ'' --xx ''rr[[--dd,,------]]'' --gg ''**..ZZ'' ---- ccoommpprreessss %% ccoommpprreessss --dd ff_T_A_B %% ccoommpprreessss --dd ff__ In the first case, the alternative glob pattern (^^**..ZZ) will be used if the first part does not generate any possible completions, while in the second case the alternative glob pattern will only be used if the rr[[...]] pattern doesn't match. BBiinnddiinnggss Each of the editor commands we have seen was actually a function bound by default to a certain key. The real names of the commands are: eexxppaanndd--oorr--ccoommpplleettee _T_A_B ppuusshh--lliinnee _E_S_C_-_Q rruunn--hheellpp _E_S_C_-_H aacccceepptt--aanndd--hhoolldd _E_S_C_-_A qquuoottee--lliinnee _E_S_C_-_' These bindings are arbitrary; you could change them if you want. For example, to bind aacccceepptt--lliinnee to _^_Z: %% bbiinnddkkeeyy ''^^ZZ'' aacccceepptt--lliinnee Another idea would be to bind the delete key to ddeelleettee--cchhaarr; this might be convenient if you use _^_H for backspace. %% bbiinnddkkeeyy ''^^??'' ddeelleettee--cchhaarr Or, you could bind _^_X_^_H to rruunn--hheellpp: %% bbiinnddkkeeyy ''^^XX^^HH'' rruunn--hheellpp -36- Other examples: %% bbiinnddkkeeyy ''^^XX^^ZZ'' uunniivveerrssaall--aarrgguummeenntt %% bbiinnddkkeeyy '' '' mmaaggiicc--ssppaaccee %% bbiinnddkkeeyy --ss ''^^TT'' ''uuppttiimmee >> '' %% bbiinnddkkeeyy ''^^QQ'' ppuusshh--lliinnee--oorr--eeddiitt uunniivveerrssaall--aarrgguummeenntt multiplies the next command by 4. Thus _^_X_^_Z_^_W might delete the last four words on the line. If you bind space to mmaaggiicc--ssppaaccee, then csh-style history expansion is done on the line whenever you press the space bar. Something that often happens is that I am typing a multiline command and discover an error in one of the previous lines. In this case, ppuusshh--lliinnee--oorr--eeddiitt will put the entire multi- line construct into the editor buffer. If there is only a single line, it is equivalent to ppuusshh--lliinnee. The --ss flag to bbiinnddkkeeyy specifies that you are binding the key to a string, not a command. Thus bbiinnddkkeeyy --ss ''^^TT'' ''uuppttiimmee\\nn'' lets you VMS lovers get the load average whenever you press _^_T. If you have a NeXT keyboard, the one with the || and \\ keys very inconveniently placed, the following bindings may come in handy: %% bbiinnddkkeeyy --ss ''\\ee//'' ''\\\\'' %% bbiinnddkkeeyy --ss ''\\ee=='' ''||'' Now you can type _A_L_T_-_/ to get a backslash, and _A_L_T_-_= to get a vertical bar. This only works inside zzsshh, of course; bbiinnddkkeeyy has no effect on the key mappings inside ttaallkk or mmaaiill, etc. Some people like to bind ^^SS and ^^QQ to editor commands. Just binding these has no effect, as the terminal will catch them and use them for flow control. You could unset them as stop and start characters, but most people like to use these for external commands. The solution is to set the _N_O_F_L_O_W_C_O_N_T_R_O_L option. This will allow you to bind the start and stop characters to editor commands, while retaining their normal use for external commands. PPaarraammeetteerr SSuubbssttiittuuttiioonn In zzsshh, parameters are set like this: %% ffoooo==bbaarr %% eecchhoo $$ffoooo bbaarr Spaces before or after the == are frowned upon: -37- %% ffoooo == bbaarr zzsshh:: ccoommmmaanndd nnoott ffoouunndd:: ffoooo Also, sseett doesn't work for setting parameters: %% sseett ffoooo==bbaarr %% sseett ffoooo == bbaarr %% eecchhoo $$ffoooo %% Note that no error message was printed. This is because both of these commands were perfectly valid; the sseett builtin assigns its arguments to the _p_o_s_i_t_i_o_n_a_l _p_a_r_a_m_e_t_e_r_s ($$11, $$22, etc.). %% sseett ffoooo==bbaarr %% eecchhoo $$11 ffoooo==bbaarr %% sseett ffoooo == bbaarr %% eecchhoo $$33 $$22 bbaarr == If you're really intent on using the csh syntax, define a function like this: %% sseett (()) {{ >> eevvaall ""$$11$$22$$33"" >> }} %% sseett ffoooo == bbaarr %% sseett ffuuuu==bbrrrrrr %% eecchhoo $$ffoooo $$ffuuuu bbaarr bbrrrrrr But then, of course you can't use the form of sseett with options, like sseett --FF (which turns off filename generation). Also, the sseett command by itself won't list all the parame- ters like it should. To get around that you need a ccaassee statement: %% sseett (()) {{ >> ccaassee $$11 iinn >> --**||++**||'''')) bbuuiillttiinn sseett $$** ;;;; >> **)) eevvaall ""$$11$$22$$33"" ;;;; >> eessaacc >> }} For the most part, this should make csh users happy. The following sh-style operators are supported in zzsshh: %% uunnsseett nnuullll %% eecchhoo $${{ffoooo--xxxxxx}} bbaarr -38- %% eecchhoo $${{nnuullll--xxxxxx}} xxxxxx %% uunnsseett nnuullll %% eecchhoo $${{nnuullll==xxxxxx}} xxxxxx %% eecchhoo $$nnuullll xxxxxx %% eecchhoo $${{ffoooo==xxxxxx}} bbaarr %% eecchhoo $$ffoooo bbaarr %% uunnsseett nnuullll %% eecchhoo $${{nnuullll++sseett}} %% eecchhoo $${{ffoooo++sseett}} sseett Also, csh-style :: modifiers may be appended to a parameter substitution. %% eecchhoo $$PPWWDD //hhoommee//lleeaarrnniinngg//ppff//zzsshh//zzsshh22..0000//ssrrcc %% eecchhoo $$PPWWDD::hh //hhoommee//lleeaarrnniinngg//ppff//zzsshh//zzsshh22..0000 %% eecchhoo $$PPWWDD::hh::hh //hhoommee//lleeaarrnniinngg//ppff//zzsshh %% eecchhoo $$PPWWDD::tt ssrrcc %% nnaammee==ffoooo..cc %% eecchhoo $$nnaammee ffoooo..cc %% eecchhoo $$nnaammee::rr ffoooo %% eecchhoo $$nnaammee::ee cc The equivalent constructs in ksh (which are also supported in zzsshh) are a bit more general and easier to remember. When the shell expands $${{ffoooo##_p_a_t}}, it checks to see if _p_a_t matches a substring at the beginning of the value of ffoooo. If so, it removes that portion of ffoooo, using the shortest possible match. With $${{ffoooo####_p_a_t}}, the longest possible match is removed. $${{ffoooo%%_p_a_t}} and $${{ffoooo%%%%_p_a_t}} remove the match from the end. Here are the ksh equivalents of the :: modifiers: %% eecchhoo $${{PPWWDD%%//**}} //hhoommee//lleeaarrnniinngg//ppff//zzsshh//zzsshh22..0000 %% eecchhoo $${{PPWWDD%%//**//**}} //hhoommee//lleeaarrnniinngg//ppff//zzsshh %% eecchhoo $${{PPWWDD####**//}} ssrrcc %% eecchhoo $${{nnaammee%%..**}} ffoooo -39- %% eecchhoo $${{nnaammee##**..}} cc zzsshh also has upper/lowercase modifiers: %% xxxx==TTeesstt %% eecchhoo $$xxxx::uu TTEESSTT %% eecchhoo $$xxxx::ll tteesstt and a substitution modifier: %% eecchhoo $$nnaammee::ss//ffoooo//bbaarr// bbaarr..cc %% llss ffoooo..cc ffoooo..hh ffoooo..oo ffoooo..pprroo %% ffoorr ii iinn ffoooo..**;; mmvv $$ii $$ii::ss//ffoooo//bbaarr// %% llss bbaarr..cc bbaarr..hh bbaarr..oo bbaarr..pprroo There is yet another syntax to modify substituted parame- ters. You can add certain modifiers in parentheses after the opening brace like: $${{((_m_o_d_i_f_i_e_r_s))_p_a_r_a_m_e_t_e_r}} For example, oo sorts the words resulting from the expansion: %% eecchhoo $${{ppaatthh}} //uussrr//bbiinn //uussrr//bbiinn//XX1111 //eettcc %% eecchhoo $${{((oo))ppaatthh}} //eettcc //uussrr//bbiinn //uussrr//bbiinn//XX1111 One possible source of confusion is the fact that in zzsshh, the result of parameter substitution is _n_o_t split into words. Thus, this will not work: %% ssrrccss==''gglloobb..cc eexxeecc..cc iinniitt..cc'' %% llss $$ssrrccss gglloobb..cc eexxeecc..cc iinniitt..cc nnoott ffoouunndd This is considered a feature, not a bug. If splitting were done by default, as it is in most other shells, functions like this would not work properly: $$ llll (()) {{ llss --FF $$** }} $$ llll ''ffuuuu bbaarr'' ffuuuu nnoott ffoouunndd bbaarr nnoott ffoouunndd %% llll ''ffuuuu bbaarr'' ffuuuu bbaarr nnoott ffoouunndd -40- Of course, a hackish workaround is available in sh (and zzsshh): %% sseettoopptt sshhwwoorrddsspplliitt %% llll (()) {{ llss --FF ""$$@@"" }} %% llll ''ffuuuu bbaarr'' ffuuuu bbaarr nnoott ffoouunndd If you like the sh behaviour, zzsshh can accomodate you: %% llss $${{==ssrrccss}} eexxeecc..cc gglloobb..cc iinniitt..cc %% sseettoopptt sshhwwoorrddsspplliitt %% llss $$ssrrccss eexxeecc..cc gglloobb..cc iinniitt..cc Another way to get the $$ssrrccss trick to work is to use an array: %% uunnsseett ssrrccss %% ssrrccss==(( gglloobb..cc eexxeecc..cc iinniitt..cc )) %% llss $$ssrrccss eexxeecc..cc gglloobb..cc iinniitt..cc or an alias: %% aalliiaass --gg SSRRCCSS==''eexxeecc..cc gglloobb..cc iinniitt..cc'' %% llss SSRRCCSS eexxeecc..cc gglloobb..cc iinniitt..cc Another option that modifies parameter expansion is _R_C_E_X_- _P_A_N_D_P_A_R_A_M: %% eecchhoo ffoooo//$$ssrrccss ffoooo//gglloobb..cc eexxeecc..cc iinniitt..cc %% sseettoopptt rrcceexxppaannddppaarraamm %% eecchhoo ffoooo//$$ssrrccss ffoooo//gglloobb..cc ffoooo//eexxeecc..cc ffoooo//iinniitt..cc %% eecchhoo ffoooo//$${{^^ssrrccss}} ffoooo//gglloobb..cc ffoooo//eexxeecc..cc ffoooo//iinniitt..cc %% eecchhoo ffoooo//$$^^ssrrccss ffoooo//gglloobb..cc ffoooo//eexxeecc..cc ffoooo//iinniitt..cc SShheellll PPaarraammeetteerrss The shell has many predefined parameters that may be accessed. Here are some examples: %% sslleeeepp 1100 && [[11]] 33882200 %% eecchhoo $$!! 33882200 %% sseett aa bb cc -41- %% eecchhoo $$## 33 %% eecchhoo $$AARRGGCC 33 %% (( eexxiitt 2200 )) ;; eecchhoo $$?? 2200 %% ffaallssee;; eecchhoo $$ssttaattuuss 11 ($$?? and $$ssttaattuuss are equivalent.) %% eecchhoo $$HHOOSSTT $$HHOOSSTTTTYYPPEE ddeennddrriittee ssuunn44 %% eecchhoo $$UUIIDD $$GGIIDD 770011 6600 %% ccdd //ttmmpp %% ccdd //hhoommee %% eecchhoo $$PPWWDD $$OOLLDDPPWWDD //hhoommee //ttmmpp %% llss $$OOLLDDPPWWDD//..ggeettwwdd //ttmmpp//..ggeettwwdd ~~++ and ~~-- are short for $$PPWWDD and $$OOLLDDPPWWDD, respectively. %% llss ~~--//..ggeettwwdd //ttmmpp//..ggeettwwdd %% llss --dd ~~++//lleeaarrnniinngg //hhoommee//lleeaarrnniinngg %% eecchhoo $$RRAANNDDOOMM 44888800 %% eecchhoo $$RRAANNDDOOMM 1111778855 %% eecchhoo $$RRAANNDDOOMM 22006622 %% eecchhoo $$TTTTYY //ddeevv//ttttyypp44 %% eecchhoo $$VVEERRSSIIOONN zzsshh vv22..0000..0033 %% eecchhoo $$UUSSEERRNNAAMMEE ppff The ccddppaatthh variable sets the search path for the ccdd command. If you do not specify .. somewhere in the path, it is assumed to be the first component. %% ccddppaatthh==(( //uussrr ~~ ~~//zzsshh )) %% llss //uussrr 55bbiinn ddiicctt llaanngg nneett ssccccss ssyyss 55iinncclluuddee eettcc lleeccttoorr nnsseerrvvee sseerrvviicceess ttmmpp 55lliibb eexxppoorrtt lliibb ooeedd sshhaarree uuccbb aaddmm ggaammeess llooccaall oolldd sskkeell uuccbbiinncclluuddee bbiinn ggeeaacc lloosstt++ffoouunndd ooppeennwwiinn ssppooooll uuccbblliibb bboooott hhoossttss mmaaccssyymmaa__441177 ppaatt ssrrcc xxppgg22bbiinn -42- ddeemmoo iinncclluuddee mmaann pprriinncceettoonn ssttaanndd xxppgg22iinncclluuddee ddiiaagg kkvvmm mmddeecc ppuubb sswwaapp xxppgg22lliibb %% ccdd ssppooooll //uussrr//ssppooooll %% ccdd bbiinn //uussrr//bbiinn %% ccdd ffuunncc ~~//ffuunncc %% ccdd %% ccdd ppuubb %% ppwwdd //uu//ppffaallssttaadd//ppuubb %% llss --dd //uussrr//ppuubb //uussrr//ppuubb PPAATTHH and ppaatthh both set the search path for commands. These two variables are equivalent, except that one is a string and one is an array. If the user modifies PPAATTHH, the shell changes ppaatthh as well, and vice versa. %% PPAATTHH==//bbiinn:://uussrr//bbiinn:://ttmmpp::.. %% eecchhoo $$ppaatthh //bbiinn //uussrr//bbiinn //ttmmpp .. %% ppaatthh==(( //uussrr//bbiinn .. //uussrr//llooccaall//bbiinn //uussrr//uuccbb )) %% eecchhoo $$PPAATTHH //uussrr//bbiinn::..:://uussrr//llooccaall//bbiinn:://uussrr//uuccbb The same is true of CCDDPPAATTHH and ccddppaatthh: %% eecchhoo $$CCDDPPAATTHH //uussrr:://uu//ppffaallssttaadd:://uu//ppffaallssttaadd//zzsshh %% CCDDPPAATTHH==//uu//ssuubbbbaarraaoo:://uussrr//ssrrcc:://ttmmpp %% eecchhoo $$ccddppaatthh //uu//ssuubbbbaarraaoo //uussrr//ssrrcc //ttmmpp In general, predefined parameters with names in all lower- case are arrays; assignments to them take the form: _n_a_m_e==(( _e_l_e_m ... )) Predefined parameters with names in all uppercase are strings. If there is both an array and a string version of the same parameter, the string version is a colon-separated list, like PPAATTHH. HHIISSTTFFIILLEE is the name of the history file, where the history is saved when a shell exits. %% zzsshh pphhooeenniixx%% HHIISSTTFFIILLEE==//ttmmpp//hhiissttoorryy pphhooeenniixx%% SSAAVVEEHHIISSTT==2200 pphhooeenniixx%% eecchhoo ffoooo ffoooo pphhooeenniixx%% ddaattee -43- FFrrii MMaayy 2244 0055::3399::3355 EEDDTT 11999911 pphhooeenniixx%% uuppttiimmee 55::3399aamm uupp 44 ddaayyss,, 2200::0022,, 4400 uusseerrss,, llooaadd aavveerraaggee:: 22..3300,, 22..2200,, 22..0000 pphhooeenniixx%% eexxiitt %% ccaatt //ttmmpp//hhiissttoorryy HHIISSTTFFIILLEE==//ttmmpp//hhiissttoorryy SSAAVVEEHHIISSTT==2200 eecchhoo ffoooo ddaattee uuppttiimmee eexxiitt %% HHIISSTTSSIIZZEE==33 %% hhiissttoorryy 2288 rrmm //ttmmpp//hhiissttoorryy 2299 HHIISSTTSSIIZZEE==33 3300 hhiissttoorryy If you have several incantations of zzsshh running at the same time, like when using the X window system, it might be preferable to append the history of each shell to a file when a shell exits instead of overwriting the old contents of the file. You can get this behaviour by setting the _A_P_P_E_N_D_H_I_S_T_O_R_Y option. In zzsshh, if you say %% >>ffiillee the command ccaatt is normally assumed: %% >>ffiillee ffoooo!! ^^DD %% ccaatt ffiillee ffoooo!! Thus, you can view a file simply by typing: %% <>ffiillee %% llss --ll ffiillee --rrww--rr----rr---- 11 ppffaallssttaadd 00 MMaayy 2244 0055::4411 ffiillee If NNUULLLLCCMMDD is unset, the shell reports an error if no com- mand is specified (like csh). %% uunnsseett NNUULLLLCCMMDD -44- %% >>ffiillee zzsshh:: rreeddiirreeccttiioonn wwiitthh nnoo ccoommmmaanndd Actually, RREEAADDNNUULLLLCCMMDD is used whenever you have a null com- mand reading input from a single file. Thus, you can set RREEAADDNNUULLLLCCMMDD to mmoorree or lleessss rather than ccaatt. Also, if you set NNUULLLLCCMMDD to :: for sh compatibility, you can still read files with << ffiillee if you leave RREEAADDNNUULLLLCCMMDD set to mmoorree. PPrroommppttiinngg The default prompt for zzsshh is: pphhooeenniixx%% eecchhoo $$PPRROOMMPPTT %%mm%%## The %%mm stands for the short form of the current hostname, and the %%## stands for a %% or a ##, depending on whether the shell is running as root or not. zzsshh supports many other control sequences in the PPRROOMMPPTT variable. %% PPRROOMMPPTT==''%%//>> '' //uu//ppffaallssttaadd//eettcc//TTeeXX//zzsshh>> %% PPRROOMMPPTT==''%%~~>> '' ~~//eettcc//TTeeXX//zzsshh>> %% PPRROOMMPPTT==''%%hh %%~~>> '' 66 ~~//eettcc//TTeeXX//zzsshh>> %%hh represents the number of current history event. %% PPRROOMMPPTT==''%%hh %%~~ %%MM>> '' 1100 ~~//eettcc//TTeeXX//zzsshh aappppllee--gguunnkkiieess..ggnnuu..aaii..mmiitt..eedduu>> %% PPRROOMMPPTT==''%%hh %%~~ %%mm>> '' 1111 ~~//eettcc//TTeeXX//zzsshh aappppllee--gguunnkkiieess>> %% PPRROOMMPPTT==''%%hh %%tt>> '' 1122 66::1111aamm>> %% PPRROOMMPPTT==''%%nn %%ww ttttyy%%ll>>'' ppffaallssttaadd FFrrii 2244 ttttyypp00>> PPRROOMMPPTT22 is used in multiline commands, like for-loops. The %%__ escape sequence was made especially for this prompt. It is replaced by the kind of command that is being entered. %% PPRROOMMPPTT22==''%%__>> '' %% ffoorr ii iinn ffoooo bbaarr ffoorr>> %% eecchhoo ''hhii qquuoottee>> -45- Also available is the RRPPRROOMMPPTT parameter. If this is set, the shell puts a prompt on the _r_i_g_h_t side of the screen. %% RRPPRROOMMPPTT==''%%tt'' %% 66::1144aamm %% RRPPRROOMMPPTT==''%%~~'' %% ~~//eettcc//TTeeXX//zzsshh %% PPRROOMMPPTT==''%%ll %%TT %%mm[[%%hh]] '' RRPPRROOMMPPTT=='' %%~~'' pp00 66::1155 pphhooeenniixx[[55]] ~~//eettcc//TTeeXX//zzsshh These special escape sequences can also be used with the --PP option to pprriinntt: %% pprriinntt --PP %%hh ttttyy%%ll 1155 ttttyypp11 The PPOOSSTTEEDDIITT parameter is printed whenever the editor exits. This can be useful for termcap tricks. To highlight the prompt and command line while leaving command output unhigh- lighted, try this: %% PPOOSSTTEEDDIITT==``eecchhoottcc ssee`` %% PPRROOMMPPTT==''%%SS%%%% '' LLooggiinn//llooggoouutt wwaattcchhiinngg You can specify login or logout events to monitor by setting the wwaattcchh variable. Normally, this is done by specifying a list of usernames. %% wwaattcchh==(( ppffaallssttaadd ssuubbbbaarraaoo ssuukktthhnnkkrr eeggssiirreerr )) The lloogg command reports all people logged in that you are watching for. %% lloogg ppffaallssttaadd hhaass llooggggeedd oonn pp00 ffrroomm mmiicckkeeyy.. ppffaallssttaadd hhaass llooggggeedd oonn pp55 ffrroomm mmiicckkeeyy.. %% ... ssuubbbbaarraaoo hhaass llooggggeedd oonn pp88 ffrroomm pphhooeenniixx.. %% ... ssuubbbbaarraaoo hhaass llooggggeedd ooffff pp88 ffrroomm pphhooeenniixx.. %% ... ssuukktthhnnkkrr hhaass llooggggeedd oonn pp88 ffrroomm ddeeww.. %% ... ssuukktthhnnkkrr hhaass llooggggeedd ooffff pp88 ffrroomm ddeeww.. If you specify hostnames with an @@ prepended, the shell will watch for all users logging in from the specified host. -46- %% wwaattcchh==(( @@mmiicckkeeyy @@pphhooeenniixx )) %% lloogg ddjjtthhoonnggss hhaass llooggggeedd oonn qq22 ffrroomm pphhooeenniixx.. ppffaallssttaadd hhaass llooggggeedd oonn pp00 ffrroomm mmiicckkeeyy.. ppffaallssttaadd hhaass llooggggeedd oonn pp55 ffrroomm mmiicckkeeyy.. If you give a tty name with a %% prepended, the shell will watch for all users logging in on that tty. %% wwaattcchh==(( %%ttttyypp00 %%ccoonnssoollee )) %% lloogg rroooott hhaass llooggggeedd oonn ccoonnssoollee ffrroomm .. ppffaallssttaadd hhaass llooggggeedd oonn pp00 ffrroomm mmiicckkeeyy.. The format of the reports may also be changed. %% wwaattcchh==(( ppffaallssttaadd ggeetttteess eeppss ddjjtthhoonnggss jjccoorrrr bbddaavviiss )) %% lloogg jjccoorrrr hhaass llooggggeedd oonn ttff ffrroomm 112288..111122..117766..33::00.. jjccoorrrr hhaass llooggggeedd oonn rr00 ffrroomm 112288..111122..117766..33::00.. ggeetttteess hhaass llooggggeedd oonn pp44 ffrroomm yyoo::00..00.. ddjjtthhoonnggss hhaass llooggggeedd oonn ppee ffrroomm ggrruummppyy::00..00.. ddjjtthhoonnggss hhaass llooggggeedd oonn qq22 ffrroomm pphhooeenniixx.. bbddaavviiss hhaass llooggggeedd oonn qqdd ffrroomm BBRRUUNNOO.. eeppss hhaass llooggggeedd oonn pp33 ffrroomm ccssxx3300::00..00.. ppffaallssttaadd hhaass llooggggeedd oonn pp00 ffrroomm mmiicckkeeyy.. ppffaallssttaadd hhaass llooggggeedd oonn pp55 ffrroomm mmiicckkeeyy.. %% WWAATTCCHHFFMMTT==''%%nn oonn ttttyy%%ll ffrroomm %%MM'' %% lloogg jjccoorrrr oonn ttttyyttff ffrroomm 112288..111122..117766..33::00.. jjccoorrrr oonn ttttyyrr00 ffrroomm 112288..111122..117766..33::00.. ggeetttteess oonn ttttyypp44 ffrroomm yyoo::00..00 ddjjtthhoonnggss oonn ttttyyppee ffrroomm ggrruummppyy::00..00 ddjjtthhoonnggss oonn ttttyyqq22 ffrroomm pphhooeenniixx..PPrriinncceettoo bbddaavviiss oonn ttttyyqqdd ffrroomm BBRRUUNNOO..ppppppll..ggoovv eeppss oonn ttttyypp33 ffrroomm ccssxx3300::00..00 ppffaallssttaadd oonn ttttyypp00 ffrroomm mmiicckkeeyy..PPrriinncceettoonn ppffaallssttaadd oonn ttttyypp55 ffrroomm mmiicckkeeyy..PPrriinncceettoonn %% WWAATTCCHHFFMMTT==''%%nn ffmm %%mm'' %% lloogg jjccoorrrr ffmm 112288..111122..117766..33::00 jjccoorrrr ffmm 112288..111122..117766..33::00 ggeetttteess ffmm yyoo::00..00 ddjjtthhoonnggss ffmm ggrruummppyy::00..00 ddjjtthhoonnggss ffmm pphhooeenniixx bbddaavviiss ffmm BBRRUUNNOO eeppss ffmm ccssxx3300::00..00 ppffaallssttaadd ffmm mmiicckkeeyy ppffaallssttaadd ffmm mmiicckkeeyy %% WWAATTCCHHFFMMTT==''%%nn %%aa aatt %%tt %%ww..'' %% lloogg jjccoorrrr llooggggeedd oonn aatt 33::1155ppmm MMoonn 2200.. jjccoorrrr llooggggeedd oonn aatt 33::1166ppmm WWeedd 2222.. ggeetttteess llooggggeedd oonn aatt 66::5544ppmm WWeedd 2222.. -47- ddjjtthhoonnggss llooggggeedd oonn aatt 77::1199aamm TThhuu 2233.. ddjjtthhoonnggss llooggggeedd oonn aatt 77::2200aamm TThhuu 2233.. bbddaavviiss llooggggeedd oonn aatt 1122::4400ppmm TThhuu 2233.. eeppss llooggggeedd oonn aatt 44::1199ppmm TThhuu 2233.. ppffaallssttaadd llooggggeedd oonn aatt 33::3399aamm FFrrii 2244.. ppffaallssttaadd llooggggeedd oonn aatt 33::4422aamm FFrrii 2244.. If you have a ..ffrriieennddss file in your home directory, a conve- nient way to make zzsshh watch for all your friends is to do this: %% wwaattcchh==(( $$((<< ~~//..ffrriieennddss)) )) %% eecchhoo $$wwaattcchh ssuubbbbaarraaoo mmaarruucchhcckk rroooott ssuukktthhnnkkrr ... If watch is set to aallll, then all users logging in or out will be reported. OOppttiioonnss Some options have already been mentioned; here are a few more: Using the _A_U_T_O_C_D option, you can simply type the name of a directory, and it will become the current directory. %% ccdd // %% sseettoopptt aauuttooccdd %% bbiinn %% ppwwdd //bbiinn %% ....//eettcc %% ppwwdd //eettcc With _C_D_A_B_L_E_V_A_R_S, if the argument to ccdd is the name of a parameter whose value is a valid directory, it will become the current directory. %% sseettoopptt ccddaabblleevvaarrss %% ffoooo==//ttmmpp %% ccdd ffoooo //ttmmpp _C_O_R_R_E_C_T turns on spelling correction for commands, and the _C_O_R_R_E_C_T_A_L_L option turns on spelling correction for all argu- ments. %% sseettoopptt ccoorrrreecctt %% ssll zzsshh:: ccoorrrreecctt ``ssll'' ttoo ``llss'' [[nnyyaaee]]?? yy %% sseettoopptt ccoorrrreeccttaallll %% llss xx..vv1111rr44 zzsshh:: ccoorrrreecctt ``xx..vv1111rr44'' ttoo ``XX..VV1111RR44'' [[nnyyaaee]]?? nn -48- //uussrr//pprriinnccttoonn//ssrrcc//xx..vv1111rr44 nnoott ffoouunndd %% llss //eettcc//ppaasswwdd zzsshh:: ccoorrrreecctt ttoo ``//eettcc//ppaasswwdd'' ttoo ``//eettcc//ppaasssswwdd'' [[nnyyaaee]]?? yy //eettcc//ppaasssswwdd If you press yy when the shell asks you if you want to cor- rect a word, it will be corrected. If you press nn, it will be left alone. Pressing aa aborts the command, and pressing ee brings the line up for editing again, in case you agree the word is spelled wrong but you don't like the correction. Normally, a quoted expression may contain a newline: %% eecchhoo '' >> ffoooo >> '' ffoooo %% With _C_S_H_J_U_N_K_I_E_Q_U_O_T_E_S set, this is illegal, as it is in csh. %% sseettoopptt ccsshhjjuunnkkiieeqquuootteess %% llss ''ffoooo zzsshh:: uunnmmaattcchheedd '' _G_L_O_B_D_O_T_S lets files beginning with a .. be matched without explicitly specifying the dot. %% llss --dd **xx** MMaaiillbbooxxeess %% sseettoopptt gglloobbddoottss %% llss --dd **xx** ..eexxrrcc ..ppnneewwsseexxppeerrtt ..xxsseerrvveerrrrcc ..mmuusshheexxppeerrtt ..xxiinniittrrcc MMaaiillbbooxxeess _H_I_S_T_I_G_N_O_R_E_D_U_P_S prevents the current line from being saved in the history if it is the same as the previous one; _H_I_S_T_I_G_- _N_O_R_E_S_P_A_C_E prevents the current line from being saved if it begins with a space. %% PPRROOMMPPTT==''%%hh>> '' 3399>> sseettoopptt hhiissttiiggnnoorreedduuppss 4400>> eecchhoo ffoooo ffoooo 4411>> eecchhoo ffoooo ffoooo 4411>> eecchhoo ffoooo ffoooo 4411>> eecchhoo bbaarr bbaarr 4422>> sseettoopptt hhiissttiiggnnoorreessppaaccee 4433>> eecchhoo ffoooo -49- ffoooo 4433>> eecchhoo ffuubbaarr ffuubbaarr 4433>> eecchhoo ffuubbaarr ffuubbaarr _I_G_N_O_R_E_B_R_A_C_E_S turns off csh-style brace expansion. %% eecchhoo xx{{yy{{zz,,aa}},,{{bb,,cc}}dd}}ee xxyyzzee xxyyaaee xxbbddee xxccddee %% sseettoopptt iiggnnoorreebbrraacceess %% eecchhoo xx{{yy{{zz,,aa}},,{{bb,,cc}}dd}}ee xx{{yy{{zz,,aa}},,{{bb,,cc}}dd}}ee _I_G_N_O_R_E_E_O_F forces the user to type eexxiitt or llooggoouutt, instead of just pressing _^_D. %% sseettoopptt iiggnnoorreeeeooff %% ^^DD zzsshh:: uussee ''eexxiitt'' ttoo eexxiitt.. _I_N_T_E_R_A_C_T_I_V_E_C_O_M_M_E_N_T_S turns on interactive comments; comments begin with a ##. %% sseettoopptt iinntteerraaccttiivveeccoommmmeennttss %% ddaattee ## tthhiiss iiss aa ccoommmmeenntt FFrrii MMaayy 2244 0066::5544::1144 EEDDTT 11999911 _N_O_B_E_E_P makes sure the shell never beeps. _N_O_C_L_O_B_B_E_R prevents you from accidentally overwriting an existing file. %% sseettoopptt nnoocclloobbbbeerr %% ccaatt //ddeevv//nnuullll >>~~//..zzsshhrrcc zzsshh:: ffiillee eexxiissttss:: //uu//ppffaallssttaadd//..zzsshhrrcc If you really do want to clobber a file, you can use the >>!! operator. To make things easier in this case, the >> is stored in the history list as a >>!!: %% ccaatt //ddeevv//nnuullll >>!! ~~//..zzsshhrrcc %% ccaatt //eettcc//mmoottdd >> ~~//..zzsshhrrcc zzsshh:: ffiillee eexxiissttss:: //uu//ppffaallssttaadd//..zzsshhrrcc %% !!!! ccaatt //eettcc//mmoottdd >>!! ~~//..zzsshhrrcc %% ... _R_C_Q_U_O_T_E_S lets you use a more elegant method for including single quotes in a singly quoted string: %% eecchhoo ''""ddoonn''\\''''tt ddoo tthhaatt..""'' ""ddoonn''tt ddoo tthhaatt.."" %% eecchhoo ''""ddoonn''''tt ddoo tthhaatt..""'' -50- ""ddoonntt ddoo tthhaatt.."" %% sseettoopptt rrccqquuootteess %% eecchhoo ''""ddoonn''''tt ddoo tthhaatt..""'' ""ddoonn''tt ddoo tthhaatt.."" Finally, _S_U_N_K_E_Y_B_O_A_R_D_H_A_C_K wins the award for the strangest option. If a line ends with ``, and there are an odd number of them on the line, the shell will ignore the trailing ``. This is provided for keyboards whose RETURN key is too small, and too close to the `` key. %% sseettoopptt ssuunnkkeeyybbooaarrddhhaacckk %% ddaattee`` FFrrii MMaayy 2244 0066::5555::3388 EEDDTT 11999911 CClloossiinngg CCoommmmeennttss I (Bas de Bakker) would be happy to receive mail if anyone has any tricks or ideas to add to this document, or if there are some points that could be made clearer or covered more thoroughly. Please notify me of any errors in this docu- ment. -51- TTaabbllee ooff CCoonntteennttss Introduction . . . . . . . . . . . . . . . . . . . . . . 1 Filename Generation . . . . . . . . . . . . . . . . . . 1 Startup Files . . . . . . . . . . . . . . . . . . . . . 5 Shell Functions . . . . . . . . . . . . . . . . . . . . 6 Directories . . . . . . . . . . . . . . . . . . . . . . 9 Directory Stacks . . . . . . . . . . . . . . . . . . . . 11 Command/Process Substitution . . . . . . . . . . . . . . 14 Redirection . . . . . . . . . . . . . . . . . . . . . . 17 Aliasing . . . . . . . . . . . . . . . . . . . . . . . . 17 History . . . . . . . . . . . . . . . . . . . . . . . . 21 Command Line Editing . . . . . . . . . . . . . . . . . . 23 Completion . . . . . . . . . . . . . . . . . . . . . . . 27 Extended completion . . . . . . . . . . . . . . . . . . 32 Bindings . . . . . . . . . . . . . . . . . . . . . . . . 35 Parameter Substitution . . . . . . . . . . . . . . . . . 36 Shell Parameters . . . . . . . . . . . . . . . . . . . . 40 Prompting . . . . . . . . . . . . . . . . . . . . . . . 44 Login/logout watching . . . . . . . . . . . . . . . . . 45 Options . . . . . . . . . . . . . . . . . . . . . . . . 47 Closing Comments . . . . . . . . . . . . . . . . . . . . 50