How to merge two files consistently line by line

Language Agnostic

Language Agnostic Problem Overview


I have two files (file1.txt & file2.txt ). The files are only examples.

How can I merge the two files, in order to create the file - merge_files.txt as example 3?

I am now writing a KornShell (ksh) script, so merge can be done with KornShell, AWK, sed, a Perl one-liner, etc.

Background - why I need to merge the files: my target is to rename the old file (exist in first field) to a new file (exist in the second field).

Example 1

File file1.txt
/etc/port1-192.9.200.1-255.555.255.0
/etc/port2-192.9.200.1-255.555.255.0
/etc/port3-192.9.200.1-255.555.255.0
/etc/port4-192.9.200.1-255.555.255.0
/etc/port5-192.9.200.1-255.555.255.0
.
.
.
.

Example 2

File file2.txt
/etc/port1-192.90.2.1-255.555.0.0
/etc/port2-192.90.2.1-255.555.0.0
/etc/port3-192.90.2.1-255.555.0.0
/etc/port4-192.90.2.1-255.555.0.0
/etc/port5-192.90.2.1-255.555.0.0
.
.
.
.

Example 3

File merge_files.txt
/etc/port1-192.9.200.1-255.555.255.0  /etc/port1-192.90.2.1-255.555.0.0
/etc/port2-192.9.200.1-255.555.255.0  /etc/port2-192.90.2.1-255.555.0.0
/etc/port3-192.9.200.1-255.555.255.0  /etc/port3-192.90.2.1-255.555.0.0
/etc/port4-192.9.200.1-255.555.255.0  /etc/port4-192.90.2.1-255.555.0.0
/etc/port5-192.9.200.1-255.555.255.0  /etc/port5-192.90.2.1-255.555.0.0
.
.
.
.
.

Example 4 (merge_files.txt structure)

first field                           second field

OLD file                              NEW file

Language Agnostic Solutions


Solution 1 - Language Agnostic

You can use paste to format the files side by side:

$ paste -d" " file1.txt file2.txt
/etc/port1-192.9.200.1-255.555.255.0 /etc/port1-192.90.2.1-255.555.0.0
/etc/port2-192.9.200.1-255.555.255.0 /etc/port2-192.90.2.1-255.555.0.0
/etc/port3-192.9.200.1-255.555.255.0 /etc/port3-192.90.2.1-255.555.0.0
/etc/port4-192.9.200.1-255.555.255.0 /etc/port4-192.90.2.1-255.555.0.0
/etc/port5-192.9.200.1-255.555.255.0 /etc/port5-192.90.2.1-255.555.0.0

E.g.:

$ paste -d" " file1.txt file2.txt | while read from to; do echo mv "${from}" "${to}"; done
mv /etc/port1-192.9.200.1-255.555.255.0 /etc/port1-192.90.2.1-255.555.0.0
mv /etc/port2-192.9.200.1-255.555.255.0 /etc/port2-192.90.2.1-255.555.0.0
mv /etc/port3-192.9.200.1-255.555.255.0 /etc/port3-192.90.2.1-255.555.0.0
mv /etc/port4-192.9.200.1-255.555.255.0 /etc/port4-192.90.2.1-255.555.0.0
mv /etc/port5-192.9.200.1-255.555.255.0 /etc/port5-192.90.2.1-255.555.0.0

Of course you would want to throw in some safety checks ([ -f "${from}" ], ...).

Disclaimer: Works only if there are no spaces in your filenames.

Solution 2 - Language Agnostic

This Perl one-liner will display the necessary renames:

perl -e 'open $f[$_-1], "file$_.txt" for 1,2; print "rename @n\n" while chomp(@n = map ''.<$_>, @f)'

If this works for you then replace the print statement with a real rename and use

perl -e 'open $f[$_-1], "file$_.txt" for 1,2; rename @n while chomp(@n = map ''.<$_>, @f)'

to do the actual renaming.

Solution 3 - Language Agnostic

paste -d " " file1.txt file2.txt

works great for this job.

But in case you are handling text files in a Windows environment and make use of GNU paste, make sure to transform the files to Unix format (CR) and do not use files with (CR-LF).

GNU paste does not seem to handle DOS formats properly and parsing is unpredictable. The expected output is erratic and unexpected without warnings.

You may use gVim to transform them easily (menu EditFile SettingsFile Format).

Solution 4 - Language Agnostic

Completely unrelated ways to achieve the OP's goal of renaming numbered files:

for f in {1..5}; do mv /etc/port$d-192.9.200.1-255.555.255.0 /etc/port$d-192.90.2.1-255.555.0.0; done

Another possibility based on rename

rename 's/192.9.200.1/192.90.2.1/' /etc/port[1-5]-192.9.200.1-255.555.255.0

Solution 5 - Language Agnostic

Command
paste file1 file2
Output
/etc/port1-192.9.200.1-255.555.255.0    /etc/port1-192.90.2.1-255.555.0.0
/etc/port2-192.9.200.1-255.555.255.0    /etc/port2-192.90.2.1-255.555.0.0
/etc/port3-192.9.200.1-255.555.255.0    /etc/port3-192.90.2.1-255.555.0.0
/etc/port4-192.9.200.1-255.555.255.0    /etc/port4-192.90.2.1-255.555.0.0
/etc/port5-192.9.200.1-255.555.255.0    /etc/port5-192.90.2.1-255.555.0.0

Solution 6 - Language Agnostic

Here's sample code to merge files in Windows CMD:

: Count number of lines to merge
for /f "tokens=*" %i in ('find /c /v "" ^< test2.txt') do set /a n=%i<nul

: Read 2 files & merge line by line
for /l %a in (1,1,%n%) do (
for /f "tokens=*" %i in ('find /v /n "" ^< test1.txt ^| find "[%a]"') do (
for /f "tokens=*" %j in ('find /v /n "" ^< test2.txt ^| find "[%a]"') do (
set a=%i
set b=%j
set a=!a:*]=!
set b=!b:*]=!
echo:!a! -- !b!
)))

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser1121951View Question on Stackoverflow
Solution 1 - Language AgnosticAdrian FrühwirthView Answer on Stackoverflow
Solution 2 - Language AgnosticBorodinView Answer on Stackoverflow
Solution 3 - Language AgnosticmigsView Answer on Stackoverflow
Solution 4 - Language AgnosticVincent FourmondView Answer on Stackoverflow
Solution 5 - Language Agnosticuser8854776View Answer on Stackoverflow
Solution 6 - Language AgnosticZimbaView Answer on Stackoverflow