Writing Aliases in csh and tcsh Simple aliases The csh and tcsh shells provide an alias command th

Writing Aliases in csh and tcsh

Simple aliases

The csh and tcsh shells provide an alias command that allows you to make up new commands as abbreviations for longer, more complex commands. For example,

alias ll ls -l
defines a command named  ll which lists files in long form ( i.e. with protections, sizes, modification dates, etc.) You can use it by itself:
ll
total 20
-rw-r--r--    1 sbloch   users        4583 Oct 13 16:10 hw2.html
-rw-r--r--    1 sbloch   users        3273 Oct 13 16:46 hw3.html
-rw-r--r--    1 sbloch   users         540 Oct 11 13:49 index.html
drwx------    2 sbloch   users        4096 Oct 11 12:01 old
or with arguments:
ll ~/html/class/271/assignments/h*
-rw-r--r--    1 sbloch   users        4583 Oct 13 16:10 /users/staff/math/sbloch/html/class/271/assignments/hw2.html
-rw-r--r--    1 sbloch   users        3273 Oct 13 16:46 /users/staff/math/sbloch/html/class/271/assignments/hw3.html
Note that the command  ll is simply replaced by  ls -l in the command line, leaving the rest intact.

Using command-line arguments

Sometimes you want an alias to deal explicitly with its arguments, rather than just leaving them at the end of the command. For example, suppose you had a file in your home directory named friends:

Joe Schmoe	123 Main Street	212-987-6543
Jane Doe	975 First Ave	516-357-6420
Bob T. Slob	111 River Road	718-432-1098
Bill T. Pill	1 South Ave	516-877-0000
and you wanted to look up entries in this file easily:
% friend Joe
Joe Schmoe	123 Main Street	212-987-6543
% friend 516
Jane Doe	975 First Ave	516-357-6420
Bill T. Pill	1 South Ave	516-877-0000
A natural way to write this is using  grep:
alias friend grep  ~/friends
doesn't work, because  grep expects the string you're searching for to be the  first argument, followed by the file you're searching. So we need to put the argument of  friend just after the word  grep, before the filename  ~/friends.

As it happens, csh records the command you typed in its history before expanding aliases, so you can use the history substitution features to find out what the arguments were to the latest command (e.g. "friend Joe"). To review...

  • !! is the whole command line
  • !* is all the arguments of the command
  • !:1 is the first argument of the command
  • !:2 is the second argument of the command
  • !$ is the last argument of the command
So let's try
alias friend grep !:1 ~/friends
Unfortunately, this doesn't work, because the shell recognizes "!:1" as a history reference  before it executes the  alias command; in other words, this takes the first argument of whatever command was executed just before the  alias, and defines  friend to always search for that word!

So we need a way to tell the shell not to try "!:1" as a history reference. As is so often the case in Unix, we do this with a backslash:

alias friend grep \!:1 ~/friends
And now the  friend command works as desired.

For another (sillier) example, suppose we wanted a thrice command which took one argument and printed it three times:

% thrice bandersnatch
bandersnatch bandersnatch bandersnatch
Our first attempt might be
alias thrice echo !:1 !:1 !:1
but again, the "!:1" is recognized before the  alias command even starts, rather than when the  thrice command is used; a working version is
alias thrice echo \!:1 \!:1 \!:1

Quoting

Protecting a sequence semicolon

Suppose we wanted the thrice command to print its argument three times, each on a separate line. An easy way to do this is with three separate echo commands, separated by semicolons:

alias thrice echo \!:1 ; echo \!:1 ; echo \!:1
Unfortunately, the shell breaks the command line at semicolons  before executing the  alias command, so this has the effect of defining thrice to be simply "echo !:1", and then printing the string "!:1" twice on separate lines immediately. We want the semicolons to apply after  thrice is expanded, rather than before it is defined. So we use single-quotes:
alias thrice 'echo \!:1 ; echo \!:1 ; echo \!:1'
which works. (In this case, double-quotes would also have worked. For reasons we'll see later, single-quotes are generally preferred for aliases.)

For another example, suppose we wanted a showstuff alias that prints out the current date, this month's calendar, the word "Files:", and a list of files in the current directory.

alias showstuff date ; cal ; echo Files: ; ls
doesn't work, because again the semicolons apply before  alias starts, rather than after  showstuff is expanded.
alias showstuff 'date ; cal ; echo Files: ; ls'
works much better.

Protecting a pipe

Suppose we want a command lnd which lists, with details, all the non-directory files in the current directory. We could try

alias lnd ls -l | grep -v ^d
(recall that in an "ls -l" listing, directories always have "d" as the first character on the line). But the shell recognizes the pipe character before the  alias command starts, so it defines  lnd to stand for "ls -l", and pipes the nonexistent output of the  alias command into  grep -v ^d, which is not what we wanted. In fact, for reasons I don't want to go into here, the  alias doesn't seem to have  any effect: the  lnd command isn't recognized! Again, we'll fix the problem with single-quotes:
alias lnd 'ls -l | grep -v ^d'
which works.

Protecting I/O redirection

The same issue arises if an alias tries to do I/O redirection. Suppose we wanted a savels command to do an ls -l but put the results into a specified file. We might try

alias savels ls -l >\!:1
but the shell interprets the > character for output redirection before  alias starts, rather than after  savels is expanded. So instead we say
alias savels 'ls -l >\!:1'

If you try this savels command and look at the resulting file, you'll notice that the file contains its own name. If we want only theother files in the directory, we can fix it:

alias savels 'ls -l | grep -v \!:1 >\!:1'

Protecting globbing wildcards

Let's go back to thrice, but suppose we wanted it to take arbitrarily many arguments and repeat them all three times:

% thrice this is a test
this is a test this is a test this is a test
We recall that !* stands for  all the arguments of the latest command, so we try
alias thrice echo \!* \!* \!*
but we immediately get an error message, before we can even try  thrice. The explanation is that the character * also means "all the filenames in the current directory", and filename globbing (expansion of *, ?, [a-z], and similar patterns) happens before  alias executes, rather than after  thrice is expanded. Once again, single quotes to the rescue:
alias thrice 'echo \!* \!* \!*'

Single vs. double quotes: protecting variable expansion

All of the examples so far would have also worked using double quotes instead of single quotes. But let's try indir, which treats its first parameter as a directory to move to, then treats the rest of the parameters as a command to execute in that directory. For example,

indir ~sbloch/html/class/271 ls -l *html
should  cd to the
~sbloch/html/class/271
directory, list all the HTML files in that directory, and  cd back to where we were before. How do we write this?
alias indir 'set current=`pwd` ; cd \!:1 ; \!:2* ; cd $current'

Now, suppose we wrote the same thing using double quotes:

alias indir "set current=`pwd` ; cd \!:1 ; \!:2* ; cd $current"
Since the expansion of shell and environment variables happens after the recognition of single quotes, but before the recognition of double quotes, the shell would expand the variable name "current" at the time  indir is  defined, rather than while it's executing. If "current" doesn't happen to be defined when you type the  alias indir ... command, you'll get an error message; if it  is defined,  indirwill work oddly:
panther% pwd
/users/staff/math/sbloch/public_html/class/archive/271/fall2005/notes
panther% indir ~sbloch/html/class/271 ls -l *html
-rw-r--r--    1 sbloch   users        5134 Oct 14 10:52 271_calendar.shtml
-rw-r--r--    1 sbloch   users        6753 Oct 15 19:43 index.html
-rw-r--r--    1 sbloch   users        6373 Apr 10  2002 old_index.html
-rw-r--r--    1 sbloch   users        8852 Sep 20 12:01 syllabus.html
panther% pwd
/users/staff/math/sbloch
because "current" happened to be  /users/staff/math/sbloch at the time I defined the alias.

On the other hand, if you actually want to use the value of a variable at the time the alias is defined rather than at the time it's used (uncommon but possible), then double quotes are the way to go.

Moral of the story

In general, unless you have a good reason not to, always put the body of an alias in single-quotes.

alias commandname 'blah blah blah blah blah'

Writing long aliases

If you're writing an alias for a multi-stage pipe, or just involving a lot of words, it can easily get too long to fit on one line comfortably. If you try to type

alias longcmd 'echo this is a very very very very very very very very
very very long alias command'
you won't get to the second line, because the shell will complain that the first line has mismatched quotation marks. So we use a backslash to tell the shell that the newline isn't actually the end of the command:
alias longcmd 'echo this is a very very very very very very very very \
very very long alias command'
This time there's no error message until you try  longcmd, at which point it prints out
this is a very very very very very very very very
csh: very: Command not found.
The backslash prevented the shell from ending the  alias command, but then  longcmd expanded into something with a newline in the middle, and the shell at  that time decided the newline meant the end of a command. So we fix it with  another backslash:
alias longcmd 'echo this is a very very very very very very very very \\
very very long alias command'
Now one of the backslashes prevents the shell from ending the  alias command, and the other is still left to prevent the shell from ending the echo command when  longcmd is expanded.

Whether you entirely understood that or not, the rule of thumb is that if an alias definition is more than one line long, put a double backslash at the end of each line except the last.


Last modified: Sun Oct 16 08:07:10 EDT 2005
Stephen Bloch / sbloch@adelphi.edu
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值