When I create
alias wd='ps -ef | grep java | awk {'print 2ドル " " 9ドル'} | egrep "(A|B|C|D)"'
or
function wd () {
ps -ef | grep java | awk '{print 2ドル}' ...
}
in my .bashrc file, I get errors. Interestingly, if I source my .bashrc file with the function, it 'compiles', but when executing, gives me:
context is
>>> \ <<< {\print
missing }
Can someone help me with this, and also answer when its better to put something in a function versus in an alias?
3 Answers 3
Why the alias doesn't work
alias wd='ps -ef | grep java | awk {'print 2ドル " " 9ドル'} | egrep "(A|B|C|D)"'
The alias
command receives three arguments. The first is the string wd=ps -ef | grep java | awk {print
(the single quotes prevent the characters between them from having a special meaning). The second argument consists of a single space character. (In .bashrc
, the positional parameters 2ドル
and 9ドル
are empty, so 2ドル
expands to a list of 0 words.) The third argument is } | egrep "(A|B|C|D)"
(again the single quotes protect the special characters).
The alias definition is parsed like any other shell command when it is encountered. Then the string defined for the alias is parsed when the alias is expanded. Here are some possible ways to define this alias. First possibility: since the whole alias definition is within single quotes, only use double quotes in the commands, which means you must protect the "
and $
meant for awk with backslashes.
alias wd='ps -ef | grep java | awk "{print \2ドル \" \" \9ドル}" | egrep "(A|B|C|D)"'
Second possibility: every character stands for itself within single quotes, except that a single quote ends the literal string. '\''
is an idiom for "single quote inside a single-quoted string": end the single-quoted string, put a literal single quote, and immediately start a new single-quoted string. Since there's no intervening space, it's still the same word.
alias wd='ps -ef | grep java | awk '\''{print 2ドル " " 9ドル}'\'' | egrep "(A|B|C|D)"'
You can simplify this a bit:
alias wd='ps -ef | grep java | awk '\''{print 2,ドル 9ドル}'\'' | egrep "(A|B|C|D)"'
Tip: use set -x
to see how the shell is expanding your commands.
Why the function doesn't work
I don't know. The part you show looks ok. If you still don't understand why your function isn't working after my explanations, copy-paste your code.
Alias or function?
Use an alias only for very simple things, typically to give a shorter name to a frequently-used command or provide default options. Examples:
alias grep='grep --color'
alias cp='cp -i'
alias j=jobs
For anything more complicated, use functions.
What you should have written
Instead of parsing the ps
output, make it generate output that suits you.
wd () {
ps -C java -o pid=,cmd= | egrep "(A|B|C|D)"
}
The problem with the alias is that quotes don't nest directly (except, as a special case, inside $()
). You need to escape the inner ones.
alias wd='ps -ef | grep java | awk {\'print 2ドル " " 9ドル\'} | egrep "(A|B|C|D)"'
# ^^ ^^
You've removed too much of the function form for me to be certain, but the error snippet is from awk
and suggests quoting or shell variable expansion problems.
As a general rule, functions are more flexible than aliases (you have no control over argument processing with aliases aside from history expansion), but aliases are a little faster, and if you end the alias with a space then the first argument gets expanded as a command (tab completion, etc.) Aliases also don't work in the file they're declared in (to avoid infinite alias expansion loops).
-
1Several errors here. Your quoting doesn't work at all: backslashes are not special inside single quotes. (See my answer if you need more explanation.) An alias ending with a space has no influence on completion in bash (I think). Aliases do work as soon as they are declared (or in bash, maybe only on the next line, but that's a bug); alias expansion loops are prevented by a completely different mechanism (an alias
foo
is not expanded in the (direct or indirect) result of the expansion offoo
).Gilles 'SO- stop being evil'– Gilles 'SO- stop being evil'2011年03月18日 19:20:34 +00:00Commented Mar 18, 2011 at 19:20
I dont think you can pass an argument to an alias. An alias is just a string replacement rule for the first word of a command.
Example:
alias wd='ps -ef | grep java | awk {'print 2ドル " " 9ドル'} | egrep "(A|B|C|D)"'
will result in the command wd arg1 arg2 arg3
being replaced and executed as
ps -ef | grep java | awk {'print " " '} | egrep "(A|B|C|D)" arg1 arg2 arg3
For everything beyond that, use functions.
-
Actually, because
2ドル
and9ドル
are inside single quotes, they won't be expanded by the shell but byawk
, which uses them as field selectors for theps
output: the uid and the first argument to the command, for Linuxps -f
. That said, the failed nested quoting means the shell was expanding them when it shouldn't have been.geekosaur– geekosaur2011年03月18日 18:53:48 +00:00Commented Mar 18, 2011 at 18:53 -
@geekosaur oh, yes, of course. I haven't looked at it that way.wnrph– wnrph2011年03月18日 18:58:19 +00:00Commented Mar 18, 2011 at 18:58
-
@geekosaur, @artistoex: Yes, you can pass an argument to an alias, and in fact it's commonly used. Here,
2ドル
and9ドル
are unprotected when the alias is defined. See my answer for the full story.Gilles 'SO- stop being evil'– Gilles 'SO- stop being evil'2011年03月18日 19:22:16 +00:00Commented Mar 18, 2011 at 19:22 -
@gilles The argument is not passed to the alias in the sense you can not effect where the original arguments will be placed in the final command string. It will always be placed at the end.wnrph– wnrph2011年03月19日 10:30:37 +00:00Commented Mar 19, 2011 at 10:30