2

This is a very similar question to How to loop over the lines of a file?.

I have a file with rows with n fields, separated by spaces. I want to loop through this file by row, and use the set the fields as variables, for use in calling information from a different file.

So, for example, my file looks like this:

A B C
D E F
H I J
K L M

I'd like to loop thru each line and set the variables to be the fields:

foreach i ( `cat file ` )
set 1st = $i[1]; set 2nd = $i[2]; set 3rd = $i[3]
end

Right now, my shell is using spaces to separate the fields, and this means I can't set the 3 variables in each row.

Were I to echo each $i - I'd see this:

A
B
C
D
....

I'd like to know how to control my loop by using only the new lines as the separators.

Here's what I really want to achieve. I want to grep rows in file A which contain 3 different values, all of which appear as space separated elements in the rows of file B. My plan was to loop thru each line in file B, setting variables for each of the (space separated) elements in that row of B, and then make use of these 3 elements. And then repeat for the next row of B. But my loop fails because it doesn't see the rows in file B. It only sees ALL the space separated elements, with no recognition of their grouping into rows of 3 elements. I hope this isn't confusing

Chris Davies
  • 116,213
  • 16
  • 160
  • 287
ZakS
  • 305
  • 3
    Please read Why is using a shell loop to process text considered bad practice? for why processing files with shells is a bad idea and see Csh Programming Considered Harmful for why it is a particularly bad idea to use csh-style shells for programming. – terdon Nov 21 '21 at 13:28
  • 1
    don't have much option re csh unfortunately, just looking for a solution – ZakS Nov 21 '21 at 13:29
  • 1
    You mean you are on a system that doesn't have sh installed and doesn't have the basic text processing tools like per, awk, sed etc? What operating system are you using? – terdon Nov 21 '21 at 13:30
  • 1
    no, I meant I am limited to using tcsh. I can certainly use sh, awk, sed. How would I do that here? – ZakS Nov 21 '21 at 13:40
  • 2
    What is the final objective here? Do you just want to print the lines to the terminal? Do you need to do some downstream processing? The usual solution is to just do whatever you want to do in awk or perl or sed or any other tool more suitable to text parsing. If you [edit] your question and explain what the final objective is, we should be able to help. – terdon Nov 21 '21 at 13:43
  • 1
    I wanted to set each field in each row (so in row 1 - set 1st = A , set 2nd =B, set 3rd = C) to create variables, work with those variables to obtain a result inside the file – ZakS Nov 21 '21 at 13:46
  • 1
    Yes, but again, no shell is a good option for this and tcsh is a particularly bad option. This is what is known as an XY problem. I suggest you [edit] your question, show us an actual example of the data and explain what result you need to get. That way, we can give you a solution that won't require using the shell. – terdon Nov 21 '21 at 13:49
  • foreach i ( `cat file ` ) unrolls all the values as separate items, as each one is separated from the next by some form of whitespace. Right there, you've lost any representation of n fields per line – Chris Davies Nov 21 '21 at 16:32
  • "I am limited to using tcsh" - but you then say "I can certainly use sh. So you're not limited to tcsh and you can use a shell that's got decent flow control loops. Remember that your interactive shell need not be the one that runs shell scripts – Chris Davies Nov 21 '21 at 16:35
  • 1
    @roaima I didn't have success running it as a shell script either. How do control the loop so it treats each row as complete unit to be worked on? – ZakS Nov 21 '21 at 19:18
  • 1
    You don't. Instead, use a tool that reads and processes the data directly. If you care to tell us what you're trying to achieve them someone here may well be able to help you – Chris Davies Nov 21 '21 at 20:20
  • I want to grep rows in file A which contain 3 different values, all of which appear as space separated elements in the rows of file B. My plan was to loop thru each line in file B, setting variables for each of the (space separated) elements in that row of B, and then make use of these 3 elements. And then repeat for the next row of B. But my loop fails because it doesn't see the rows in file B. It only sees ALL the space separated elements, with no recognition of their grouping into rows of 3 elements. I hope this isn't confusing. – ZakS Nov 21 '21 at 20:53
  • Is the example file your A or your B? Do you have a matching example of the other file you can add to your question? – Chris Davies Nov 21 '21 at 22:26

3 Answers3

0

I don't know if the original problem was communicated clearly enough, but it seems that I have a problem in my shell environment looping thru rows of a text file where the rows have space separated elements, such as, for example

row 1: A B C
row 2: D E F

I've found a workaround for this by converting each row into one element, in a way I can parse it later for uses beyond (I think) the scope of this question . So my two rows above become

row 1: A_B_C
row 2: D_E_F

in such a format, my foreach loop sees each row as a single element and if I now need B in my first iteration, I can use, for example:

foreach i ( `cat <file>` )
foreach? set a = `echo $i | awk -F '_' '{print($2)}'`
foreach? echo $a
foreach? end

This should echo:

B
E

which would be the 2nd element in each row of my file

Thanks to everyone who took an interest and if there is a more elegant way to do this, please let me know.

ZakS
  • 305
  • 1
    Write the whole thing in awk. or perl. or almost any language that isn't sh/bash/ksh/zsh/etc or csh/tcsh. The big mistake you are making is trying to do text processing in csh (and it wouldn't be much better in a bourne-like shell - less buggy, but still awful). If you want to do text processing, then use a language suited to it, like awk or perl. Shells are good at setting up pipes and feeding data into other programs that do data processing. They are terrible at doing data processing themselves. – cas Nov 21 '21 at 22:46
  • 1
    A sh or csh script's role in any non-trivial data processing task is to be a wrapper around other programs - grep, awk, sed, perl, and many others - that do the actual work. shells do the setup, other programs do the work. – cas Nov 21 '21 at 22:48
0

I wish some people would just answer the question. Is it possible? Yes. Is it recommended? No. But if you HAVE to you can do it by following the answer of this stackoverflow:

https://stackoverflow.com/questions/40926372/how-to-iterate-every-line-from-variable-on-the-basis-of-new-line-character-inste

0

Word splitting is something csh almost got better than the Bourne shell. In csh, "`cmd`" splits the output of cmd into its non-empty lines not doing globbing while `cmd` splits on space tab or newline and does globbing. So you could do:

set n = 0 noglob
foreach line ( "`cat file`" )
  @ n++
  set field = ( $line )
  echo First field of line $n is $field[1], second is $field[2]
end

Though of course to do text processing by lines and fields, you'd use something like perl or awk, not a shell loop.