0

Ive got a file called school.test and it looks like this:

David       maths
Sam         maths
Sam         english
Simon       french
Simon       english

I want to write a for loop which reads this txt file up line by line and assign values that it is reading up on that line to different variables and run it through a command. Problem is I don't know how to set the first value as a variable and the second value as a different variable.

For example for the first line the for loop reads it would look something like this:

for line in `cat/home/school.test`
do
positionClient -name [variable=David] -class [variable=math]
done

and so on and so forth. How do I do this?

nrs90
  • 168
  • 1
  • 3
  • 19
  • http://stackoverflow.com/questions/9293887/in-bash-how-do-i-convert-a-space-delimited-string-into-an-array might help – Doon Apr 28 '15 at 12:48
  • 1
    I have no idea what the title has to do with the question. – Ignacio Vazquez-Abrams Apr 28 '15 at 12:48
  • http://mywiki.wooledge.org/BashFAQ/001 – Politank-Z Apr 28 '15 at 12:48
  • is this an exercise, or a practical (e.g. work, non-school, non-training) problem? i'll reserve the right to "solve the problem", rather than answer the question. why? unless the OP states something to the effect: 'this is a problem designed to show how to ..." i can assume that's NOT the point, and the problem's solution MAY be better solved by another means. at the very least this should get a. the problem posers to make more relevant examples, and b. the problem solvers to be open about their needs. – Marty McGowan Apr 29 '15 at 22:30

4 Answers4

3
$ while read name subject
> do
>   echo "Name: $name, Subject: $subject"
> done <<< 'David       maths
> Sam         maths
> Sam         english
> Simon       french
> Simon       english'
Name: David, Subject: maths
Name: Sam, Subject: maths
Name: Sam, Subject: english
Name: Simon, Subject: french
Name: Simon, Subject: english

Just redirect from a file instead of a herestring when you want to do the real thing.

Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
  • so I'm trying this method but its not working for me: `while read name subject do echo "symbol: $symbol"; echo "inventory: $inventory" done <<< /srg/pro/data//school.txt` – nrs90 Apr 28 '15 at 13:28
  • `<<<` is for a herestring. File input redirection uses `<` as always. – Ignacio Vazquez-Abrams Apr 28 '15 at 13:38
  • and you need to read "awk", the preferred (e.g. non-perl) way of dealing with (essentially) tables in unix. _then_ when you're comfortable with awk, you should download RDB, e.g. search for /rdb -- unix realational database managment, schaefer, manis and jorgenson. it will change your life. – Marty McGowan Apr 29 '15 at 22:15
3

You can use the builtin read for this:

cat /home/school.test | while read name class ; do 
    positionClient -name "$name" -class "$class"
done

I prefer the pipe with cat since using I/O redirection with a while loop looks a bit odd ("what is done doing with this file??"):

while read name class ; do 
    positionClient -name "$name" -class "$class"
done < /home/school.test

Note that you have to use the second approach if you want to share variables between the loop body and code after the loop. When using a pipe, the while loop will be executed in a subshell (in a different process) and all modifications to variables inside of the loop will be lost when the loop ends.

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
  • 2
    Using the redirect doesn't look odd at all, and avoids running in a subshell. – William Pursell Apr 28 '15 at 12:53
  • To add to @WilliamPursells comment, it also allows variables set in the loop to be used outside(as it is not a subshell). –  Apr 28 '15 at 13:02
  • @WilliamPursell: I agree with the subshell problem but what is `done` doing with the file? Also, having the input at the end of a code block is weird. And when the body of the loop is big, this is easily overlooked. – Aaron Digulla Apr 28 '15 at 13:02
  • What about `while read name class ; do ..stuff..; done < /home/school.test` to avoid a **UUoC** (unnecessary use of `cat`) and spawning an additional separate subshell? (just to add formal terminology) – David C. Rankin Apr 28 '15 at 13:09
0

if you insist on using the shell loop, then:

for line in `cat school.test`
do
    set -- $line   # $1 is NAME, and $2 is CLASS. 
    # NB since awk didn't distinguish separator, NO NEED to quote $1, $2
    positionClient -name $1 -class $2
done

OR, here's a one-liner:

awk 'BEGIN { fmt="positionClient -name %s -class %s\n"; }; { print fmt, $1, $2 }' school.test | sh -x
Marty McGowan
  • 356
  • 2
  • 10
-1

There are various ways to get the values into different variables. One method is already mentioned in the other answers, i.e., using the built in read.

Allow me to explain another approach. Here is one approach using awk. It might not be the most optimal (because of the subshell thingy) but it works.

for line in `cat school.test`
do
    name=`echo $line | awk '{print $1}'`
    class=`echo $line | awk '{print $2}'`
    positionClient -name "$name" -class "$class"
done
meetrp
  • 155
  • 9
  • question use of "optimal". "optimal' should have less to do with PERFOMANCE, and more to to with SIMPLE to READ by a PERSON. not that yours isn't and you've identified the SUBoptimality without reconizing thet a single awk, if you insist, could do the job. see the use of "SET -- " below. – Marty McGowan Apr 29 '15 at 22:23
  • @MartyMcGowan: Your solution is good. And, I do understand how the `set --` works. But please help me understand how the `set` approach has a better readability than the `awk` approach? Also I mentioned, it was **one** approach and not the **only** approach. – meetrp Apr 30 '15 at 06:01