2

I have seven (or eight and so on) files with same number of lines.

file1

1.001
1.002
1.003
1.004

file2

2.001
2.002
2.003
2.004

file3

3.001
3.002
3.003
3.004

etc.

Desired output:

1.001;2.001;3.001;4.001;5.001;6.001;7.001
1.002;2.002;3.002;4.002;5.002;6.002;7.002
1.003;2.003;3.003;4.003;5.003;6.003;7.003
1.004;2.004;3.004;4.004;5.004;6.004;7.004

How to do it with short script in awk?

  • 7
    Why not just something like paste -d\; file{1..8} or paste -d\; file*? – steeldriver Jun 19 '16 at 19:49
6

As steeldriver said, the reasonable way to do this is with paste:

$ paste -d';' file*
1.001;2.001;3.001;4.001;5.001;6.001;7.001;8.001
1.002;2.002;3.002;4.002;5.002;6.002;7.002;8.002
1.003;2.003;3.003;4.003;5.003;6.003;7.003;8.003
1.004;2.004;3.004;4.004;5.004;6.004;7.004;8.004

But, if you must use awk:

$ awk '{a[FNR]=a[FNR](FNR==NR?"":";")$0} END{for (i=1;i<=FNR;i++) print a[i]}' file*
1.001;2.001;3.001;4.001;5.001;6.001;7.001;8.001
1.002;2.002;3.002;4.002;5.002;6.002;7.002;8.002
1.003;2.003;3.003;4.003;5.003;6.003;7.003;8.003
1.004;2.004;3.004;4.004;5.004;6.004;7.004;8.004

The awk script keeps all the data in memory. If the files are large, this could be a problem. But, for this task, paste is better and simpler anyway.

How it works

In this script a is an array with a[i] being the output for line i. As we read through each of the subsequent files, we append the new information for line i to the end of a[i]. After we have finished reading the files, we print out the values in a. In more detail:

  • a[FNR]=a[FNR](FNR==NR?"":";")$0

    FNR is the line number of the current file we are reading and $0 are the contents of that line. This code adds $0 on to the end of a[FNR]. Except if we are still reading the first file, we put in a semicolon before $0. This is done using the complex looking ternary statement: (FNR==NR?"":";"). This is really just a if-then-else command. If we are reading the first file, that is if FNR==NR, then it returns an empty string "". If not, it returns a semicolon, ;.

  • END{for (i=1;i<=FNR;i++) print a[i]}

    After we have finished reading all the files, this prints out the data that we have accumulated in array a.

0

POSIX Awk; this works with an arbitrary amount of files, and the files don’t even have to have the same amount of lines. The script keeps going until all files are out of lines:

BEGIN {
  do {
    br = ch = 0
    while (++ch < ARGC)
      if (getline < ARGV[ch]) {
        printf ch < ARGC - 1 ? $0 ";" : $0 RS
        br = 1
      }
  } while (br)
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.