0

I'm quite new to Shell Scripting. Right now I'm trying to figure out a shell script code that would allow me to read through all the rows of a .csv file and get only the column header for each row.

For each row, an 'X' is marked on certain columns (to represent that the Name was present for that row). I want to develop a script where upon giving the name of the first row (eg. 'row1'), the output will give me the corresponding name of the header of columns that had 'X' marked. This is a CSV file so columns that are not marked with 'X' are just blanks with the ; delimiter.

Input

Index,Name1,Name2,Name3,Name4
row1,X,,X       
row2,,,X,              
row3,X,X,X,     

If I search for 'row1', the output would be

Output

row1  Name1 Name3

If I search for 'row3', the output would be

row3   Name1  Name2  Name3 

I'd like the output to be tab delimited but if that's not possible then comma delimited would be fine too. I'm trying to do this by first using grep on the name of the rows and then piping the output. However, I'm not sure how to formulate a script that would print out the name of the header if an 'X' is marked. I've an idea of using something along that lines of grep -w 'row1' and awk -F , 'NR==1 { for (i=1;i<=NF;++i) if ($i=="X") { n=i;print $n }}' but I'm not sure how to string it together.

Any help would be greatly appreciated!

1
  • 1
    @pLumo Just made the changes
    – derrick
    Jan 5, 2022 at 7:49

2 Answers 2

3

Split the header into an array, and use them from there, e.g.:

getpattern.awk

BEGIN { FS="," }

NR==1 { split($0, colhead); next }

$1 ~ pat {
  printf "%s", $1
  for (i=2; i<=NF; i++) {
    if ($i ~ /X/)
      printf "\t%s", colhead[i]
  }
  print ""
}

Run it like this, e.g.:

awk -f getpattern.awk pat='row1|row3' infile.csv

Output:

row1    Name1   Name3
row3    Name1   Name2   Name3
4
  • 1
    Note that if there are many rows, row1|row3 might also match row11 and row308.
    – Kusalananda
    Jan 5, 2022 at 8:42
  • @they: in that case limit the pattern with anchors, e.g.: ^(row1|row3)$
    – Thor
    Jan 5, 2022 at 9:50
  • This works perfectly! Could you explain how the line of code works? Right now I'm trying to modify the code: there are two Indexes Index 1 and Index 2, and searching either indexes would print both indexes, along with the corresponding header names like this row1(index1) row1(index2) Name1 Name3.
    – derrick
    Jan 5, 2022 at 12:05
  • 1
    @omphanik: You should probably post this as a new question. Remember to include example input-/output-data and your current progress
    – Thor
    Jan 5, 2022 at 13:30
1

I would use a dedicated csv parser, e.g. python's csv module would do:

import csv
with open('file.csv') as csvfile:
    reader = csv.DictReader(csvfile)
    for row in reader:
        print(row["Index"], *[item[0] for item in row.items() if item[1] == "X"], sep=" ")

Output:

row1 Name1 Name3
row2 Name3
row3 Name1 Name2 Name3

You must log in to answer this question.

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