4

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

grep  `date '+%d/%b/%Y'` access.logs  | egrep 2765330645ae47d292c9ceac725d744e.py |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 2765330645ae47d292c9ceac725d744e.py |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????

5 Answers 5

5

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 2765330645ae47d292c9ceac725d744e.py |
                 awk '\''{print $1, $4, $5, $7, $8, $9, $10}'\'' |
                 sort | uniq -c -w15 | sort -n'
2
  • 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
    Commented Sep 27, 2009 at 4:07
  • 1
    "Functions are not inheritied by subshells" - But you can do export -f functionname Commented Sep 27, 2009 at 18:37
6

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 2765330645ae47d292c9ceac725d744e.py |awk '{print $1, $4, $5, $7, $8, $9, $10}' | sort |uniq -c -w15 |sort -n; }

That works exactly as an alias.

2
  • 1
    Ah! Nagul knows why it doesn't work :)
    – A Dwarf
    Commented Sep 26, 2009 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.
    – user4358
    Commented Sep 26, 2009 at 23:51
4

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 2765330645ae47d292c9ceac725d744e.py |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 2765330645ae47d292c9ceac725d744e.py |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 2765330645ae47d292c9ceac725d744e.py |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 2765330645ae47d292c9ceac725d744e.py |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.

3

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 2765330645ae47d292c9ceac725d744e.py |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 2765330645ae47d292c9ceac725d744e.py |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.

0

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'

You must log in to answer this question.

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