Using “diff” and “patch”

The “diff” utility is a familiar one to experienced unix users.  However, it may be less familiar to those who have only recently started to use linux.  The are command line tools, so this post is mostly for those users who like to experiment with what can be done at the command line.  I also briefly discuss “patch”, because that utility uses the output of “diff”.

Simply stated, “diff” is a utility for showing the differences between two files.  It is mainly useful for text files, and is most important for files that have a common origin, from which they have been modified.

I’ll illustrate with an example from configuration files used with “ssh”.  I recently installed opensuse 12.1, and ssh was part of that installation.  But, of course, I wanted to tweak the configuration to bring it more to my liking.  So, in the illustrations, the file “ssh_config.dist” is the version of the file that came with the distribution and was automatically installed.  And “ssh_config” is the version of the file after my minor tweaking.

I use the “diff” command to show the changes.

% diff ssh_config.dist ssh_config
58a59
>     NoHostAuthenticationForLocalhost yes
77c78
< HashKnownHosts yes
---
> HashKnownHosts no

The line that begins with “%” is the command that I typed.  The remaining lines are the output from “diff”.  Note that it is best to use “diff” in the form

diff old-file-version new-file-version

The output amounts to simple editing commands to produce the changes.  At line 58 in the old file a (the a) a line which will be line 59 in the new file.  And at line 77 in the old file (line 78 in the new file) change the line from the first form to the second.  The “<” and “>” characters indicate which is the old and which the new.

If we add a “-c” option to the “diff” command line, we get what is called a context diff:

% diff -c ssh_config.dist ssh_config
diff -c ssh_config{.dist,}
*** ssh_config.dist     2011-11-24 12:08:48.738529004 -0600
--- ssh_config  2011-11-22 09:59:59.282000002 -0600
***************
*** 56,61 ****
--- 56,62 ----
  #   PermitLocalCommand no
  #   GSSAPIAuthentication no
  #   GSSAPIDelegateCredentials no
+     NoHostAuthenticationForLocalhost yes
  
  # Set this to 'yes' to enable support for the deprecated 'gssapi' authentication
  # mechanism to OpenSSH 3.8p1. The newer 'gssapi-with-mic' mechanism is included
***************
*** 74,79 ****
  
  # This will hash new host keys and make them so unusable for malicious
  # people or software trying to use known_hosts to find further hops.
! HashKnownHosts yes
  
  #   ProxyCommand ssh -q -W %h:%p gateway.example.com
--- 75,80 ----
  
  # This will hash new host keys and make them so unusable for malicious
  # people or software trying to use known_hosts to find further hops.
! HashKnownHosts no
  
  #   ProxyCommand ssh -q -W %h:%p gateway.example.com
The context diff output provides some context around the changed lines.  It also lists the names of the files being compared.   That makes it easier to read.  The output still contains line numbers.  Lines to be removed start with "-", lines to be added start with "+" and lines to be changed are prefixed with "!". Instead of "-c" we can use the "-u" option, so that the output is what is called a unified diff.  Here's what that looks like:
% diff -u ssh_config.dist ssh_config
--- ssh_config.dist     2011-11-24 12:08:48.738529004 -0600
+++ ssh_config  2011-11-22 09:59:59.282000002 -0600
@@ -56,6 +56,7 @@
 #   PermitLocalCommand no
 #   GSSAPIAuthentication no
 #   GSSAPIDelegateCredentials no
+    NoHostAuthenticationForLocalhost yes
 
 # Set this to 'yes' to enable support for the deprecated 'gssapi' authentication
 # mechanism to OpenSSH 3.8p1. The newer 'gssapi-with-mic' mechanism is included
@@ -74,6 +75,6 @@
 
 # This will hash new host keys and make them so unusable for malicious
 # people or software trying to use known_hosts to find further hops.
-HashKnownHosts yes
+HashKnownHosts no
 
 #   ProxyCommand ssh -q -W %h:%p gateway.example.com
That's a more readable and useful output.  As with the context diff, it lists the file names near the top of the output, and provides context.  A line beginning with "-" is to be removed and a line beginning with "+" is to be added.  A change is indicated by a removed line and an added line. The patch command The output of "diff" indicates how to change an old version of the file to bring it to the new version.  The patch command can use the "diff" output, and then make those file changes.  If possible, use a unified diff output to produce a patch file.  If "-u" is not recognized by your version of "diff", then use a context diff. Suppose that I had tweaked both "ssh_config" and "sshd_config", and that I had also created a file "ssh_known_hosts".  I could now create a patch file with all of those changes:
% diff -u ssh_config.dist ssh_config > /tmp/ssh-patches
% diff -u sshd_config.dist sshd_config >> /tmp/ssh-patches
% diff -u /dev/null ssh_known_hosts >> /tmp/ssh-patches

To describe, I put the unified diff for the ssh_config changes into the file "/tmp/ssh-patches".  I then appended the unified diff output for the sshd_config changes.  And, finally, I appended the changes from an empty file ("/dev/null") to the new file "ssh_known_hosts".  I could now copy that file "/tmp/ssh-patches" to another computer with a newly installed opensuse 12.1.  And then I could apply the same changes with:

# patch < /tmp/ssh-patches

Note that this patch command would have to be run by root, since only root has permission to update those configuration files.

 

Advertisements

About Neil Rickert

Retired mathematician and computer scientist who dabbles in cognitive science.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: