1

I have a variable LINE and want to use it with awk to pull out the contents of the line numbered LINE from table.txt and make that a new variable called NAME which is then used to grep another file.

NAME=`awk 'FNR==$LINE' < table.txt`
echo "this is $NAME"

Seems to be close, but not quite the syntax.

If I use:

NAME=`awk 'FNR==1' < table.txt`
echo "this is $NAME"

Then echo gives me the first line of table.txt, if I use 2 I get the 2nd line, 3 the 3rd line, then I stopped variations.

Thanks for any advice. EDITed first post formatting faux pas.

Sam
  • 11
  • 2
  • Those "weird apostrophes" are called "backticks", and if you would take a moment to read about formatting code in your question you could get them to display correctly. – larsks May 26 '16 at 19:26
  • 2
    See: [How to use shell variables in awk script](http://stackoverflow.com/q/19075671/3776858) – Cyrus May 26 '16 at 19:27

2 Answers2

2

You're looking for:

NAME=`awk -v line="$LINE" 'FNR==line' < table.txt`

but the backticks notation is obsolete so this is better:

NAME=$(awk -v line="$LINE" 'FNR==line' < table.txt)

and you should never use all-upper-case for variable names unless they are exported (in shell) to avoid clashing with builtin names so really it should be:

name=$(awk -v line="$line" 'FNR==line' < table.txt)

but whatever you're doing is almost certainly the wrong approach and should be done entirely within awk. Make sure you fully understand everything discussed in why-is-using-a-shell-loop-to-process-text-considered-bad-practice if you're considering using shell to manipulate text.

Community
  • 1
  • 1
Ed Morton
  • 188,023
  • 17
  • 78
  • 185
  • 1
    Backticks are not *deprecated*! At least not by POSIX. That's just a common rumor. But `$()` is definitely the better choise! – hek2mgl May 26 '16 at 19:32
  • Actually the backticks appear in so much, important?, ancient? scripts, I'm afraid of the day when they deprecate and then consequently remove them.. :) Ok, you might argue that they will not upgrade bash in a nuclear power plant. But who knows... – hek2mgl May 26 '16 at 19:38
  • 2
    Definitely! Not at last to ease the typing for the programmer. – hek2mgl May 26 '16 at 19:40
  • 1
    ++; re deprecation debate: what's important is that backticks are _not_ deprecated in the sense of "this will stop working in a future version"; however, `$(...)` is a _more modern, superior alternative_; the Bash v4 man page simply calls backticks the "old-style backquote form of substitution" (without mentioning deprecation); similarly, the POSIX standard also doesn't declare the syntax _deprecated_, but clearly recommends use of `$(...)` for nested substitutions and "complex scripts" - see the comment thread on [this answer](http://stackoverflow.com/a/36732882/45375). – mklement0 May 26 '16 at 19:42
  • 1
    Yes that sounds appropriate! I admit that when reading - new - code backticks are kind of a low quality indicator for me. Mostly that continues with unquoted variables and so on. Any new code should use `$()` instead of backticks. – hek2mgl May 26 '16 at 19:50
  • 1
    updated my answer to say obsolete instead of deprecated and yes, use of backticks is a red flag that someone doesn't know what they're doing just like unquoted variables, UUOC, and multiple other oddities. Deleting my comments now. – Ed Morton May 26 '16 at 19:52
  • 1
    I would keep them. It's an interesting discussion and good reference. (But I'm fine with whatever you prefer) – hek2mgl May 26 '16 at 19:59
  • I'm afraid "obsolete" isn't really the right word either, because it implies "no longer in use". "Obsolescent" is slightly better, but still implies that it is in the _process of_ going away, which probably won't happen in this case. I can't really think of a single English word that pithily conveys "won't break if you use it, but it's better not to use it anymore". – mklement0 May 26 '16 at 20:02
  • keeping backticks, and other old fashioned styles supported is a help to novices like me a month into programming after a 20 year hiatus (from BASIC) as we google for answers to questions, and gradually learn to do things the modern way. It is pretty frustrating to be using a years old reply to our latest question which has a ton of votes but doesn't seem to work anymore. And thanks for the advice. – Sam May 26 '16 at 20:28
  • Someone was still using BASIC 20 years ago??? It's been 35 years since I last programmed in it and I thought it was dying then... :-). – Ed Morton May 26 '16 at 21:56
2

To complement Ed Morton's helpful awk-based answer:

If you only need to extract a single line by index, sed allows for a more concise solution that is also easier to optimize (note that I've changed the variable names to avoid all-uppercase variable names):

name=$(sed -n "$line {p;q;}")
  • -n tells sed not to print (possibly modified) input lines by default
  • $line, assuming this shell variable expands it to a positive integer (see caveat below), only matches the input line with that (1-based) index.
  • {p;q;}, prints (p) the matching line, then exits the overall script immediately (q) as an optimization (no need to read the remaining lines).

Note:

  • For more complex sed scripts it is NOT a good idea to use a double-quoted shell string with shell-variable expansion as the sed script, because understanding what is interpreted by the shell up front vs. what sed ends up seeing as a result can become confusing.

  • Heed Ed's point that you're likely better off solving your problem with awk alone, given that awk can do its own regex matching (probably no need for grep).

Community
  • 1
  • 1
mklement0
  • 382,024
  • 64
  • 607
  • 775