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.
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.
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]}"
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 :-))
Commented
Aug 11, 2014 at 13:19
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.
Commented
Aug 11, 2014 at 14:25
array+=
seems not suited in this case. I've never seen it's use earlier though.. but it seems quite useful!
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"
set -f
) as you don't want that part of the split+glob operator here.
Commented
Aug 11, 2014 at 13:53