Super User is a question and answer site for computer enthusiasts and power users. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I want to save the following commandline sequence as a bash alias:

grep  `date '+%d/%b/%Y'` access.logs  | egrep |awk '{print $1, $4, $5, $7, $8, $9, $10}' | sort |uniq -c -w15 |sort -n

It works fine form the commandline, but fails when I try to set it as an alias. I tried adding the following to .bash_profile:

alias downloads="grep  `date '+%d/%b/%Y'` access.logs  | egrep |awk '{print $1, $4, $5, $7, $8, $9, $10}' | sort |uniq -c -w15 |sort -n"

and I get the following errors:

-bash-3.2$ downloads
awk: {print , , , , , , 0}
awk:        ^ syntax error
awk: {print , , , , , , 0}
awk:          ^ syntax error
awk: {print , , , , , , 0}
awk:            ^ syntax error
awk: {print , , , , , , 0}
awk:              ^ syntax error
awk: {print , , , , , , 0}
awk:                ^ syntax error
awk: {print , , , , , , 0}
awk:                  ^ syntax error

What am I doing wrong????

share|improve this question
up vote 5 down vote accepted

Frankly, by the time a command gets that big, I'd make it into a script and not an alias. One advantage of a script is that you make it work with more files than just 'access.logs'.

That command sequence involves both single quotes and back-quotes - that always adds to the fun. Generally, you are better off using $(command args) in place of back-quotes.

When you use the double quotes around the alias, the back-quoted commands are executed as the alias is created - unless the shell has a different way of interpreting things when they define the alias. Also, $var expressions are evaluated inside double quotes, so your awk errors show that you have no arguments in the current shell.

So, if you must use an alias, then you probably need to use single quotes around the whole expression, plus for each single quote that appears in the expression, replace it with the sequence quote-backslash-quote-quote: '\''. The first quote terminates the current quoted string; the backslash quote represents a literal quote; the final quote restarts the quoted string.

That leads to:

alias downloads='grep  `date '\''+%d/%b/%Y'\''` access.logs |
                 egrep |
                 awk '\''{print $1, $4, $5, $7, $8, $9, $10}'\'' |
                 sort | uniq -c -w15 | sort -n'
share|improve this answer
This is great advice! You can also create a 'bash function', but indeed a script is likely preferred (at least for variable scoping purposes). Functions are not inheritied by subshells, but scripts can still be found via $PATH – ericslaw Sep 27 '09 at 4:07
"Functions are not inheritied by subshells" - But you can do export -f functionname – Dennis Williamson Sep 27 '09 at 18:37

I'm a little green on Linux, so I'm unsure exactly why it doesn't work. But you can use a function instead.

In .profile/.bashrc create a new function:

downloads() { grep  `date '+%d/%b/%Y'` access.logs  | egrep |awk '{print $1, $4, $5, $7, $8, $9, $10}' | sort |uniq -c -w15 |sort -n; }

That works exactly as an alias.

share|improve this answer
Ah! Nagul knows why it doesn't work :) – A Dwarf Sep 26 '09 at 23:38
(+1) Unless I had a valid reason to prefer an alias over a function, I'd actually prefer this. This is cleaner and more obvious than the escaped version of the alias. – nagul Sep 26 '09 at 23:51

Since the alias is defined within double quotes, the date command gets executed at the time of definition of the alias, and the $1 variables get expanded too. You can check this by looking up the alias after you define it:

$ alias downloads="grep  `date '+%d/%b/%Y'` access.logs  | egrep |awk '{print $1, $4, $5, $7, $8, $9, $10}' | sort |uniq -c -w15 |sort -n"
$ alias downloads
alias downloads='grep  27/Sep/2009 access.logs  | egrep |awk '\''{print , , , , , , 0}'\'' | sort |uniq -c -w15 |sort -n'

You should be able to fix this by escaping the date call and the $1 variables:

$ alias downloads="grep  \`date '+%d/%b/%Y'\` access.logs  | egrep |awk '{print \$1, \$4, \$5, \$7, \$8, \$9, \$10}' | sort |uniq -c -w15 |sort -n"
$ alias downloads
alias downloads='grep  `date '\''+%d/%b/%Y'\''` access.logs  | egrep |awk '\''{print $1, $4, $5, $7, $8, $9, $10}'\'' | sort |uniq -c -w15 |sort -n'

Check if you're able to run this successfully. Ideally, you'd define the alias in single-quotes, but the presence of single quotes within the alias itself makes that tricky in your situation.

share|improve this answer

Another variation is to use single quotes for the outer ones and escape and quote the inner ones. You can choose whichever method (this one or the one in nagul's answer) makes the least ugly result for a particular situation.

alias downloads='grep  $(date '\''+%d/%b/%Y'\'') access.logs  | egrep |awk '\''{print $1, $4, $5, $7, $8, $9, $10}'\'' | sort |uniq -c -w15 |sort -n'

You'll probably notice that this is what alias prints out anyway if you escape all the dollar signs.

I took the liberty of changing the backticks into $() for readability and versatility.

If you use nagul's method (including double quotes for the outer ones) and $() instead of backticks, all you have to escape is dollar signs.

alias downloads="grep  \$(date '+%d/%b/%Y') access.logs  | egrep |awk '{print \$1, \$4, \$5, \$7, \$8, \$9, \$10}' | sort |uniq -c -w15 |sort -n"

Which makes for an easy to remember and very consistent method.

share|improve this answer

How would you use the value you got from awk and store it a variable? This is what I am starting with.

alias xx2='xrandr | awk '\''$2=="connected"{s=$1} END{print s}'\'''

This is what I am trying to do.

VAR=$(xrandr | awk '$2=="connected"{s=$1} END{print s}'); xrandr --output $VAR --mode 1024x768 --rate 60; xrandr --output LVDS1 --left-of $VAR; xrandr --output LVDS1 --primary; unset VAR;

This was my first idea. I saw it is not assigning any value to VAR after I try to open up OMG.

alias xx2='VAR=$(xrandr | awk '\''$2=="connected"{s=$1} END{print s}'\''); echo $VAR > OMG'

share|improve this answer

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .