1

Looking to extract the position of the third field, entered by the user, from the file "schemas.txt"

schemas="schemas.txt"
for i in ${schemas[@]};
do
    awk '{for(i=1;i<=NF;i++)if($i=="$3")print i}'
done 

Any ideas as to why I'm stuck in an infinite loop here?

EDIT: Added an example below.

In schemas.txt, the second line is "People height weight age race occupation"

Assuming the user enters "age" as the their third parameter, I would like the line to be parsed and "4" to be returned as it is the fourth word in the string.

Conman
  • 13
  • Sure you're in an infinite loop? Your terminal may seem to hang, as your awk reads from it not having an input file. Does it exit on -D? And, aside, the i shell variable is NOT the i within awk... – RudiC Oct 23 '18 at 22:24
  • @RudiC, it does close on CTRL-D (usually I use CTRL-C to stop it), does this mean something specifically? – Conman Oct 23 '18 at 22:26
  • Yes, that means it reads from your terminal. Offer it a file. – RudiC Oct 23 '18 at 22:27
  • @RudiC I'm sorry, but would the first for loop not be what I need to open a file? I was under the assumption that the awk statement would be searching each line of the schemas.txt file – Conman Oct 23 '18 at 22:30
  • Yes - if offered that file. The shell for loop just sets the i shell variable to the "schemas.txt" string as that's the only element of the schemas variable (which is not an array, btw), and then runs the awk script reading from terminal. Offer it a file, e.g $i, expanded to schemas.txt. – RudiC Oct 23 '18 at 22:34
  • What position do you want? The line number where some value appears as the third field? Or something else? I'm not sure what "the position of the third field" means, surely it's always the third field, right? :) What should the user input? – ilkkachu Oct 23 '18 at 22:35
  • @ilkkachu I added an edit to make my question a bit more clear. – Conman Oct 23 '18 at 22:40
  • @Conman, ah you mean "$3" as in the shell parameter, the third command line argument to the script? This can be a bit confusing since both the shell and awk use $<number> for somewhat similar but really different purposes... – ilkkachu Oct 23 '18 at 22:43
  • @RudiC, so the awk statement is just searching "schemas.txt" as opposed to the entire file ? – Conman Oct 23 '18 at 22:44
  • @ilkkachu, yes exactly, I was spacing out a bit and forgot the term parameter and field seemed fitting at the time – Conman Oct 23 '18 at 22:47

1 Answers1

1

If I got your intention right, I don't think you need the shell loop. Instead, give awk the name(s) of the file(s) to read on the command line. We can pass the keyword to look for with -v, it sets an awk variable from the command line.

So, for every line that contains 'age', this would print the field number(s) where it appears:

$ cat schemas.txt
People height weight age race occupation
age is first on this line
$ keyword=age
$ awk -vk="$keyword" '{ for (i = 1 ; i <= NF ; i++) if($i == k) print i }' schemas.txt 
4
1

Of course the fixed keyword is just for an example, you can use awk -vk="$3", and skip the extra variable.

In general, that looks like it could be useful to print the line numbers too, you could use print NR, i to do that.


Here,

schemas="schemas.txt"
for i in ${schemas[@]};
do
    awk '{for(i=1;i<=NF;i++)if($i=="$3")print i}'
done 

schemas only contains schemas.txt, so that's what the shell variable i gets set to in the loop. It's unused within the loop, though, so the loop doesn't really do much. The i in the awk script is independent from the shell i.

awk would seem to hang here, since by default it reads from stdin. Also, "$3" isn't expanded by the shell within the single quotes, so awk would look for a field literally containing $3.

The loop would make more sense with multiple files:

files=(file1.txt file2.txt)
for file in "${files[@]}"; do
    awk '{...}' "$file"
done

but even then you might as well pass all the files to awk in one go:

awk '{...}' "${files[@]}"
ilkkachu
  • 138,973
  • Thank you thank you thank you! Just trying to understand this a bit more, could you do the same command on a single line if you open the line first? Assuming $line contains the same line above keyword="$3" echo $line | awk -vk="$keyword" '{ for (i = 1 ; i <= NF ; i++) if($i == k) print i }' – Conman Oct 23 '18 at 23:05
  • @Conman, yees, but that would be slow, you'd run a copy of awk for each input line. See: https://unix.stackexchange.com/q/169716/170373 . Also, use quotes around the variable, echo "$line"(https://unix.stackexchange.com/q/68694/170373). And yeah, awk -vk="$3" would work directly, I just used the extra variable since it felt clearer – ilkkachu Oct 24 '18 at 08:28