-1

File1:

A
B
C 
D

File2:

E
F
G
H

How would I get Output:

A
BF
C
DH
Jeff Schaller
  • 66,199
  • 35
  • 114
  • 250
tw2000
  • 21
  • 1
  • 4
    Welcome to UNIX & Linux at Stack Exchange. Please review the [tour] and the [How to ask a good question](https://unix.stackexchange.com/help/how-to-ask) section of the Help Center, the edit your original question and include details such as what environment you are working in, what you have already tried, any errors encountered, etc. – 0xSheepdog May 24 '19 at 03:25
  • If any of the answers solves your issue, please consider ["accepting" the answer](https://unix.stackexchange.com/help/someone-answers). This is the best way to show gratitude on this site. Accepting an answer not only marks the question as resolved, but also signals to _future readers_ that the accepted answer actually solved the issue. More information about this is available here: https://unix.stackexchange.com/help/someone-answers – Kusalananda May 24 '19 at 19:33

6 Answers6

4

You could do:

paste -d '\n' file1 file2 | sed -n 'p;n;n;N;s/\n//p' > output

paste zips the two files, alternating one line of each, and sed prints the first, discards the second, appends the 4th to the 3rd and joins them and starts again with the next lines.

Or with GNU sed:

paste -d '\n' file1 file2 | sed '2~4d' | paste -sd '\n\0\n' - > output

Where sed just discards the 2nd out of every 4 lines from the output of the zipping paste and the second paste does the joining.

Or, still with GNU sed:

sed 'z;n' file2 | paste -d'\0' file1 - > output

Where sed zaps one line (in other sed implementations, you can use s/.*//) and gets and prints the next so we can paste it to file1.

Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501
3
$ awk '{ getline other <"file2" } { print $0 (FNR % 2 == 0 ? other : "") }' file1
A
BF
C
DH

For each line of file1 read, this awk script also reads a line from file2 and stores it in the variable other. It then proceeds to print the line from file1 concatenated with the variable other, or nothing if the line number is odd.


A shell loop that would do the same thing:

n=0
while IFS= read -r a; do
    n=$(( n + 1 ))

    IFS= read -r b <&3

    [ "$(( n % 2 ))" -ne 0 ] && b=""
    printf '%s%s\n' "$a" "$b"
done <file1 3<file2

This loop loops over file1, each line being read into $a, and for each iteration also reads a line from file2 (over file descriptor 3) into $b. If the number of lines read from file1 so far is odd, $b is set to an empty string. Both $a and $b are then printed.


Using paste and GNU sed, and assuming that neither file contains tab characters (as they don't do in the question):

paste file1 file2 | sed '1~2s/\t.*//;s/\t//'

The paste will produce the contents of the two files side by side, separated by a tab character. The sed expression would first delete everything from the tab onwards on odd lines, and then delete all remaining tab characters.

With the same assumptions, the whole sed command above could be replaced by awk:

paste file1 file2 | awk -F '\t' '{ print $1 (FNR % 2 == 0 ? $2 : "") }'
Kusalananda
  • 320,670
  • 36
  • 633
  • 936
  • @olejorgenb The loop, as it is written now, will stop when `file1` ends. To stop earlier if `file2` ends, test the return status of the second `read`, possibly by changing that line into `IFS= read -r b <&3 || break`. – Kusalananda Jul 16 '22 at 12:38
  • @olejorgenb You could even change the loop into `while IFS= read -r a && IFS= read -r b <&3; do ...; done – Kusalananda Jul 16 '22 at 12:39
  • (Sorry, I could have been clearer) Yes, but I'd like a general function which can zip `N` streams: `zip <(seq 100000) <(cat file) <(cat file2)` – olejorgenb Jul 16 '22 at 12:40
  • @olejorgenb This sounds like a new question to me. You should ask it separately. – Kusalananda Jul 16 '22 at 12:44
1

Use

awk 'NR==FNR {a[NR]=$0;next} FNR%2==0 { a[FNR]=a[FNR]$0}  END{for ( i in a) print a[i]}' file1 file2

E.g.

#!/bin/bash
echo "a
B
C
D" > file1
echo 'aa
Gd
Er
Yu
Ee
Tt' > file2
awk 'NR==FNR {a[NR]=$0;next} FNR%2==0 { a[FNR]=a[FNR]$0}  END{for ( i in a) print a[i]}' file1 file2

You will get output

a
BGd
C
DYu
Tt
Prvt_Yadav
  • 5,732
  • 7
  • 32
  • 48
1

With perl also it is possible to interleave the lines from two files in the desired manner. File 2 is on std in and file 1 is an argument to perl. The line from file2 is added alternately, then the newline is removed.

$ perl -pe '($_ .= ($,,$,.<STDIN>)[$|--]) =~ s/\n(?!\z)//' File1 < File2
Rakesh Sharma
  • 804
  • 1
  • 5
  • 7
0

using GNU sed, we may do it as follows:

sed -e 'R file2' file1 | sed -Ee 'N;N;N;s/\n.*(\n.*)\n/\1/'

wherein we emulate the paste via sed and then string the 4 lines together and manipulate in such a manner so as to delete the 2nd and remove the newline between the 3rd and 4th. Repeat this process for the next 4-line slot.

Rakesh Sharma
  • 393
  • 1
  • 3
0

Assuming input is on files z7 z8:

paste -d'\0' <(cat z7) <(sed '1~2s/^.*$//' z8)

produces:

A
BF
C
DH

This first deletes all characters on odd lines, leaving the newline. The paste then concatenates the files using a NULL character (thanks to thread paste files without delimiter for the NULL tip).

This was on a system like:

OS, ker|rel, machine: Linux, 3.16.0-7-amd64, x86_64
Distribution        : Debian 8.11 (jessie) 
bash GNU bash 4.3.30
sed (GNU sed) 4.2.2
paste (GNU coreutils) 8.23

Best wishes ... cheers, drl

drl
  • 838
  • 7
  • 8