How to make a table using bash shell?

Viewed 49

I have multiple text files that have their own column. I hope to combine them into one text file like a table not a long column.

I tried 'paste' and 'column', but it did not make the shape that I wanted.

When I used the paste with two text files, it made a nice table.

paste height_1.txt height_2.txt > test.txt

The trouble starts from three or more text files.

paste height_1.txt height_2.txt height_3.txt > test.txt

At a glance, it seems nice. But when I plot the each column in the text.txt file in gnuplot(p "text.txt"), I could find some unexpected graph different from the original file especially in its last part.

enter image description here

The shape of the table is ruined in a strange way in the test.txt, causing the graph weird.

How could I make a well-structured table in the text file with bash shell?

Is it not useful to do this work with bash shell?

If yes, I will try this with python.

Height files are extracted from other *.csv files using awk.

Thank you so much for reading this question.

1 Answers

awk with simple concatenation can take the records for as many files as you have and join them together in a single output file for further processing. You simply provide the multiple input files as the files for awk to read and then concatenate each record using FNR (file record number) as an index and then use the END rule to print the combined records from all files.

For example, given 3 data files, e.g. data1.txt - data3.txt each with an integer in each row, e.g.

$ cat data1.txt 
1
2
3
$ cat data2.txt 
4
5
6

(7-9 in data3.txt, and presuming you have an equal number of records in each input file)

You could do:

awk '{a[FNR]=(FNR in a) ? a[FNR] "\t" $1 : $1} END {for (i in a) print a[i]}' data1.txt data2.txt data3.txt

(using a tab above with "\t" for the separator between columns of the output file -- you can change to suit your needs)

The result of the command above would be:

1       4       7
2       5       8
3       6       9

(note: this is what you would get with paste data1.txt data2.txt data3.txt, but presuming you have input that is giving paste problems, awk may be a bit more flexible)

Or using a "," as the separator, you would receive:

1,4,7
2,5,8
3,6,9

If your data file has more fields than a single integer and you want to compile all fields in each file, you can assign $0 to the array instead of the first field $1.

Spaced and formatted in multi-line format (for easier reading), the same awk script would be

awk '
  { 
    a[FNR] = (FNR in a) ? a[FNR] "\t" $1 : $1
  }
  END {
    for (i in a)
      print a[i]
  }
' data1.txt data2.txt data3.txt 

Look things over and let me know if I misunderstood your question, or if you have further questions about this approach.

Related