1

This is my command:

cat httpd.conf | grep ^LogFormat | awk -F\" '{print $(NF)}'

Output of this:

commonsess
common

or can be any number of values, I need to store these values in an array and print one by one...using their index number.

3 Answers 3

2

Using arrays or loops in shells is often signs of bad coding practice. A shell is a tool to run other commands. awk is the typical command to do complicated tasks with fields in text records. You want to call awk once for your task, not a loop where you're going to run hundreds of commands.

If you want to print an index and last field name for the lines starting with ^LogFormat, it's:

awk '/^LogFormat/{print n++, $NF}' httpd.conf

No need for cat (which is for concatenating), nor grep (awk is a superset of grep) or a shell array or a shell loop.

2

To strat with, using cat, grep and awk is usually wrong. You now have

cat /etc/httpd/conf/httpd.conf | grep ^LogLevel | awk -F\" '{print $(NF)}'

To read the lines in an array you can use read

while read -rd '' -a array
 do array+=("$REPLY")
 done < <(awk -F\" '/^LogFormat/{ print $(NF)}' httpd.conf)
printf '%s\n' "${array[0]}"
4
  • Your code doesn't make much sense as currently written. Aug 11, 2014 at 12:55
  • 1
    I meant that your array+=("$REPLY") for instance doesn't make much sense. Where's that REPLY coming from? Why read blank delimited fields of NUL delimited records? (and there's definitely nothing personal against you :-)) Aug 11, 2014 at 13:19
  • @StéphaneChazelas array+=.. is indeed useless in this case since the stdin is not user input but it's a file. And yes delimiter is set to indicate NULs or \0 ending of the arguments passed to the array otherwise unexpected result can occur. Aug 11, 2014 at 14:25
  • I'm with Stephane here. The array+= seems not suited in this case. I've never seen it's use earlier though.. but it seems quite useful!
    – holasz
    Aug 11, 2014 at 14:36
0

In short,
you can use:

a=( $(awk '/^LogFormat/{print $(NF)}' httpd.conf) )

to get the words from httpd.conf into the array variable a.

You can access the elements by their index now:

$ echo ${a[2]}
common

Explained and illustrated

Assingning arrays:

$ a=( e1 e2 e3 )
$ echo "count: ${#a}, a[2]: \"${a[2]}\""  
count: 3, a[2]: "e2"

Some shell setup:

This is not needed for this example where we know we have only words as values, but in general, it is very important.
We need the option -f to prevent globbing if the values contain * or ?.
Also, we should set the internal field separator IFS according to our data, if it's not simple words (and save and restore it).

$ # set -f
$ # IFS=$'\n'

Our test input:

$ in=httpd.conf
$ grep '^LogFormat' "$in"  | awk -F\" '{print $(NF)}'
 combined
 common
 referer
 agent

With your original command:

$ a=( $(cat "$in" | grep '^LogFormat' | awk -F\" '{print $(NF)}') )
$ echo "count: ${#a}, a[2]: \"${a[2]}\""
count: 4, a[2]: " common"

With the shorter version of @StéphaneChazelas:

$ a=( $(awk '/^LogFormat/{print $(NF)}' $in) )
$ echo "count: ${#a}, a[2]: \"${a[2]}\""  
count: 4, a[2]: "common"
1
  • You should also disable globbing (set -f) as you don't want that part of the split+glob operator here. Aug 11, 2014 at 13:53

You must log in to answer this question.

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