94

What's the easiest/quickest way to interleave the lines of two (or more) text files? Example:

File 1:

line1.1
line1.2
line1.3

File 2:

line2.1
line2.2
line2.3

Interleaved:

line1.1
line2.1
line1.2
line2.2
line1.3
line2.3

Sure it's easy to write a little Perl script that opens them both and does the task. But I was wondering if it's possible to get away with fewer code, maybe a one-liner using Unix tools?

Cyrus
  • 84,225
  • 14
  • 89
  • 153
Frank
  • 64,140
  • 93
  • 237
  • 324

6 Answers6

178
paste -d '\n' file1 file2
codaddict
  • 445,704
  • 82
  • 492
  • 529
  • 4
    N.B. on some platforms `paste` is rather limited - e.g. on Solaris you can have at most 12 input files, and output lines are limited to 511 characters. – user667489 Dec 03 '15 at 19:14
  • 2
    And then use this together with process substitution in an example like `paste -d '\n' <(find /) <(find /)` and realize how much better this is than first writing the results to a file in every way, disk usage, memory usage, parallelization, cancelability... – masterxilo Nov 20 '18 at 21:12
  • 4
    Wow, [`paste`](https://en.wikipedia.org/wiki/Paste_(Unix))! Going back to 1979 with [AT&T UNIX 32v](http://gunkies.org/wiki/32v). Well done, sir. – emallove Nov 22 '18 at 13:55
  • 1
    Wow., an admirably concise solution! – AndreyS Scherbakov Jul 26 '21 at 07:42
11

Here's a solution using awk:

awk '{print; if(getline < "file2") print}' file1

produces this output:

line 1 from file1
line 1 from file2
line 2 from file1
line 2 from file2
...etc

Using awk can be useful if you want to add some extra formatting to the output, for example if you want to label each line based on which file it comes from:

awk '{print "1: "$0; if(getline < "file2") print "2: "$0}' file1

produces this output:

1: line 1 from file1
2: line 1 from file2
1: line 2 from file1
2: line 2 from file2
...etc

Note: this code assumes that file1 is of greater than or equal length to file2.

If file1 contains more lines than file2 and you want to output blank lines for file2 after it finishes, add an else clause to the getline test:

awk '{print; if(getline < "file2") print; else print ""}' file1

or

awk '{print "1: "$0; if(getline < "file2") print "2: "$0; else print"2: "}' file1
samgak
  • 23,944
  • 4
  • 60
  • 82
5

@Sujoy's answer points in a useful direction. You can add line numbers, sort, and strip the line numbers:

(cat -n file1 ; cat -n file2 )  | sort -n  | cut -f2-

Note (of interest to me) this needs a little more work to get the ordering right if instead of static files you use the output of commands that may run slower or faster than one another. In that case you need to add/sort/remove another tag in addition to the line numbers:

(cat -n <(command1...) | sed 's/^/1\t/' ; cat -n <(command2...) | sed 's/^/2\t/' ; cat -n <(command3) | sed 's/^/3\t/' )  \
   | sort -n  | cut -f2- | sort -n | cut -f2-
Community
  • 1
  • 1
Joshua Goldberg
  • 5,059
  • 2
  • 34
  • 39
5

With GNU sed:

sed 'R file2' file1

Output:

line1.1
line2.1
line1.2
line2.2
line1.3
line2.3
Cyrus
  • 84,225
  • 14
  • 89
  • 153
0

Here's a GUI way to do it: Paste them into two columns in a spreadsheet, copy all cells out, then use regular expressions to replace tabs with newlines.

Dwedit
  • 618
  • 5
  • 11
-1
cat file1 file2 |sort -t. -k 2.1

Here its specified that the separater is "." and that we are sorting on the first character of the second field.

Sujoy
  • 8,041
  • 3
  • 30
  • 36
  • I don't understand how this works. For example, there is no colon in the sort input? Can you explain more? – Frank Oct 25 '10 at 14:31
  • my bad, changed the ':' to '.' its just the separator, if not specified sort uses blank to separate fields. `man sort` for more info. – Sujoy Oct 25 '10 at 15:05
  • 7
    This answer assumes the input actually takes the literal form described in the question. I think that was supposed to be illustrative. It would be possible to transform each input file that way, but it would be way more passes through the data. codaddict's answer is better. – Phil Miller Oct 25 '10 at 15:07
  • @Novelocrat: Yep, this is just another way to do it :) – Sujoy Oct 25 '10 at 15:12