I'm translating a csh script to bash an came across a line that looks like

@ lines = `grep num_lines ../config.txt | awk '{printf("%d",int($2))}' `

What does the '@' do here? I found some documentation stating that csh uses '@' for expressions. However, this looks like a normal variable assignment to me. When I run the grep and awk part of the code in bash the output is an integer with a preceding '%d', e.g. '%d 12045'.

  • Are you sure that the awk command says print and not printf? – Scott May 11 '19 at 4:26
  • That line's broken and never worked properly. It will die out with an Ambiguous error. (or Expression Syntax in tcsh). – mosvy May 11 '19 at 5:53
  • @Scott You are right, it's printf indeed. – Loibologic May 12 '19 at 17:10
  • No need for grep. Use lines=$(awk '/num_lines/ {print $2}' ../config.txt) or even lines=$(awk '$1=="num_lines" {print $2}' ../config.txt) – roaima May 12 '19 at 19:17

Well, it’s impossible to know what the author of that script was thinking.  But here are some observations:

  • If the awk command, indeed, says printf, then it is printing the integer value of the second string on the input line.
  • As roaima commented, and as I have been known to comment, awk is a very powerful program.  You almost never need to run it in combination with grep, sed, or another awk.  So
    grep num_lines filename | awk '{ printf("%d", int($2)) }'
    can be written
    awk '/num_lines/ { printf("%d", int($2)) }' filename
  • As I mentioned above, int($2) gives you the integer part of the second string on the input line.  So, if the config file says num_lines   foo, you will get 0.  If it says num_lines   3.14, you will get 3.  It seems unlikely that you would need to take such precautions with a well-formed configuration file.
  • In any case,
    printf("%d", int($2))
    is overkill.  As far as I can tell,
    printf("%d", $2)
    print int($2)
    are (almost) exactly equivalent.
  • The one difference that I can identify is that the printf version doesn’t write a newline at the end:
    $ echo "num_lines   42" | awk '{printf("%d", $2)}'; date
    42Mon, May 13, 2019 12:00:00 AM
    $ echo "num_lines   42" | awk '{print int($2)}'; date
    Mon, May 13, 2019 12:00:01 AM
    but this isn’t really relevant, since `…` strips off a trailing newline.
  • You say “this looks like a normal variable assignment to me”.  But users of [t]csh know that it doesn’t allow
    you have to say
    set variable=value
    @ variable=expr
    Of course a simple integer constant is a valid expr, so the author may simply be using @ instead of set because it’s shorter and they know that the value is an integer.

So the statement is setting the lines variable to the value of num_lines from ../config.txt.

| improve this answer | |
  • Thanks for the comprehensive answer! I did not know this convenient way to look for specific strings with awk. lines=$( awk '/num_lines/ {print int($2)}' ../config.txt ) works perfect (in bash). – Loibologic May 13 '19 at 12:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.