Linux Commands – diff
Hello Everyone
Welcome to CloudAffaire and this is Debjeet.
In the last blog post, we have discussed cat command in Linux which is used to print file content in standard output in Linux.
https://cloudaffaire.com/linux-commands-cat/
In this blog post, we will discuss diff command in Linux. diff stands for difference and in the simplest case, two file names FROM-FILE and TO-FILE are given, and diff compares the contents of FROM-FILE and TO-FILE. If one file is a directory and the other is not, diff compares the file in the directory whose name is that of the non-directory. The non-directory file must not be ‘-‘.
If two file names are given and both are directories, diff compares corresponding files in both directories, in alphabetical order; this comparison is not recursive unless the ‘–recursive’ (‘-r’) option is given. diff never compares the actual contents of a directory as if it were a file. The file that is fully specified may not be standard input, because standard input is nameless and the notion of “file with the same name” does not apply. diff options begin with ‘-‘, so normally file names may not begin with ‘-‘. However, ‘–‘ as an argument by itself treats the remaining arguments as file names even if they begin with ‘-‘.
Linux Commands – diff:
diff command compares the contents of two files and outputs in standard output. The output format can be default one (–normal), context (–content) or unified (–unified). With –normal (default behavior of diff) format, the difference between the two files is printed. If both file contents are identical, diff returns nothing. If there is a difference, diff command will print the difference. In the 1st line in diff command, the normal output gives a summary of the type of change along with the line number where the change happened. line numbers can be clubbed together if there is a change in consecutive lines.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
########################### ## Linux Commands | diff ## ########################### ## Prerequisites: One Unix/Linux/POSIX-compliant operating system with bash shell ##----- ## diff ##----- ## diff [option]... files ## compare two files with diff command (normal output) ## Normal Output: ## ## ## change_type: ## a ==> something has been added ## c ==> something has been changed ## d ==> something has been deleted echo -e "one\ntwo\nthree\nfour" > myfile1 ## create some files echo -e "one\ntwo\nthree\nfour" > myfile2 diff myfile1 myfile2 ## returns nothing echo -e "one\ntwo\n3\n4" > myfile2 ## change line 3 and 4 in target file diff myfile1 myfile2 ## returns ## 3,4c3,4 ==> line 3 to 4 has been changed (c), lines are clubbed (3,4) with comma ## < three ==> < represents source value ## < four ## --- ==> --- denotes the difference ## > 3 ## > 4 ==> > represents target value echo -e "1\ntwo\n3\nfour" > myfile2 ## change line 1 and 3 diff myfile1 myfile2 ## returns ## 1c1 ==> line 1 has been changed (c), lines are not clubbed as change is not in consicutive lines ## < one ==> < represents source value ## --- ==> --- denotes the difference ## > 1 ==> > represents target value ## 3c3 ==> line 3 has been changed (c), lines are not clubbed as change is not in consicutive lines ## < three ==> < represents source value ## --- ==> --- denotes the difference ## > 3 ==> > represents target value echo -e "one\ntwo\nthree" > myfile2 ## delete line 4 diff myfile1 myfile2 ## returns ## 4d3 ==> line 4 is deleted (d) ## < four ==> < represents source value echo -e "one\ntwo\nthree\nfour\nfive" > myfile2 ## add new line 5 diff myfile1 myfile2 ## returns ## 4a5 ==> line 5 is added (a) ## > five ==> > represents target value rm my* |
You can use diff -c or -C NUM or –context[=NUM] options to display the output in context format. In context format, 1st file creation time-stamp is printed followd by the differences where – (minus) represents delete, + (plus) represents add and ! (bang) represents change. *** <line_start,line_end> *** represents the source file and — <line_start,line_end> — represents the target file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
## compare two files with diff command (context output) ## Context Output: ## *** ## --- ## - (minus) ==> represents delete ## + (plus) ==> represents add ## ! (bang) ==> represents change echo -e "1\n2\n3\n4" > myfile1 ## create some files echo -e "1\n2\n3\n4" > myfile2 diff -c myfile1 myfile2 ## returns nothing echo -e "2\n1\n4\n5\n6" > myfile2 ## do some changes diff -c myfile1 myfile2 ## returns the difference ## returns ==> ## *** myfile1 2020-05-17 05:01:52.166885504 +0000 ## --- myfile2 2020-05-17 05:03:39.768638069 +0000 ## *************** ## *** 1,4 **** ==> source file with line numbers ## - 1 ==> delete ## 2 ## ! 3 ==> change ## 4 ## --- 1,5 ---- ==> target file with line numbers ## 2 ## ! 1 ## 4 ## + 5 ==> add ## + 6 rm my* |
You can use diff -u or -U NUM or –unified[=NUM] options to output NUM (default 3) lines of unified context. In unified format, 1st file creation time-stamp is printed followed by the differences where – (minus) represents delete, + (plus) represents add and space represents no change. @@ <source_file_line_no> <target_file_line_no> @@
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
## compare two files with diff command (unified output) ## Unified Output: ## @@ ## - (minus) ==> represents delete ## + (plus) ==> represents add ## space ==> represents no change echo -e "1\n2\n3\n4" > myfile1 ## create some files echo -e "1\n2\n3\n4" > myfile2 diff -u myfile1 myfile2 ## returns nothing echo -e "2\n1\n4\n5\n6" > myfile2 ## do some changes diff -u myfile1 myfile2 ## returns the difference ## returns ## --- myfile1 2020-05-17 10:37:06.813119533 +0000 ## +++ myfile2 2020-05-17 10:37:27.920676874 +0000 ## @@ -1,4 +1,5 @@ ## -1 ## 2 ## -3 ## +1 ## 4 ## +5 ## +6 |
You can use diff -q or –brief options to report only when files differ. Does not displays the difference, only prints that the files differ.
1 2 3 4 5 6 7 |
## Display only when the files differ echo -e "1\n2\n3\n4" > myfile1 ## create some files echo -e "1\n2\n3\n4" > myfile2 diff -q myfile1 myfile2 ## returns nothing echo -e "2\n1\n4\n5\n6" > myfile2 ## do some changes diff -q myfile1 myfile2 ## returns Files myfile1 and myfile2 differ |
You can use diff -s or –report-identical-files options to report when two files are the same. Returns the difference in normal format if the files differ.
1 2 3 4 5 6 7 |
## Display only when the files are same echo -e "1\n2\n3\n4" > myfile1 ## create some files echo -e "2\n1\n4\n5\n6" > myfile2 diff -s myfile1 myfile2 ## returns the difference in normal format echo -e "1\n2\n3\n4" > myfile2 ## do some changes diff -s myfile1 myfile2 ## returns Files myfile1 and myfile2 are identical |
You can use diff -e or -ed options to output the difference to an ed script and then use the ed script the make the source file same as target file.
1 2 3 4 5 6 7 8 9 10 11 12 |
## Make both files consistant using diff -e and ed commands echo -e "1\n2\n3\n4" > myfile1 ## create some files echo -e "1\n2\n3\n4\n5" > myfile2 diff myfile1 myfile2 ## display the difference diff -e myfile1 myfile2 > myedscript ## creates an ed script cat myedscript echo "w" >> myedscript ## instruct ed to write to make the changes ed - myfile1 < myedscript ## execute the ed script on myfile1 cat myfile1 ## 5 added to myfile1 diff myfile1 myfile2 ## both files are now identical |
You can use diff -n or –rcs options to output an RCS format diff used by RCS programs. like diff -f except that each command specifies the number of lines affected.
1 2 3 4 5 6 |
## Display the difference in Revision Control System (RCS) format. echo -e "1\n2\n3\n4" > myfile1 ## create some files echo -e "1\n2\n3\n4\n5" > myfile2 diff -n myfile1 myfile2 ## display the difference in RCS format diff myfile1 myfile2 ## display the difference in notmal format |
You can use diff -y or –side-by-side options to output in two columns. In the output, < denotes delete and > denotes add.
1 2 3 4 5 |
## Display the difference in two columns output. echo -e "1\n2\n3\n4" > myfile1 ## create some files echo -e "1\n2\n4\n6\n5" > myfile2 diff -y myfile1 myfile2 ## displays the output in two cloumns. |
You can use diff -W or –width=NUM options to output at most NUM (default 130) print columns. This option is used with –side-by-side option to define the maximum column width.
1 2 3 4 5 6 7 |
## Control the width of column in side by side option echo -e "1\n2\n3\n4" > myfile1 ## create some files echo -e "1\n2\n4\n6\n5" > myfile2 diff --side-by-side --width=10 myfile1 myfile2 ## displays the output in two cloumns with column width=10. diff --side-by-side myfile1 myfile2 ## output without the --width option |
You can use diff –left-column option to output only the left column of common lines in side by side format.
1 2 3 4 5 6 |
## Display only the left column of common lines echo -e "1\n2\n3\n4" > myfile1 ## create some files echo -e "1\n2\n3\n6\n5" > myfile2 diff --left-column myfile1 myfile2 ## displays left column of common lines |
You can use diff –suppress-common-lines option to suppress common lines in the output.
1 2 3 4 5 6 |
## Display only the left column of excluding the common lines echo -e "1\n2\n3\n4" > myfile1 ## create some files echo -e "1\n2\n3\n6\n5" > myfile2 diff --suppress-common-lines myfile1 myfile2 ## displays left column excluding common lines |
You can use diff –label=LABEL option to display LABEL instead of file name and timestamp in the context format and unified format.
1 2 3 4 5 6 7 |
## Display LABEL instead of file name and timestamp in the context format and unified format. echo -e "1\n2\n3\n4" > myfile1 ## create some files echo -e "1\n2\n3\n6\n5" > myfile2 diff -u myfile1 myfile2 ## displays file name and timestamp diff -u --label=file1 --label=file2 myfile1 myfile2 ## displays labels |
You can use diff -t or –expand-tabs options to expand tabs to spaces in the output, to preserve the alignment of tabs in the input files.
1 2 3 4 5 6 7 |
## Display tabs to spaces in the output echo -e "1\t2\n3\n4" > myfile1 ## create some files echo -e "1 2\n5\n4" > myfile2 diff -t myfile1 myfile2 ## expands tab in space diff myfile1 myfile2 ## output without -t option |
You can use diff -T or –initial-tab options to make tabs line up by prepending a tab.
1 2 3 4 5 6 7 8 |
## Prepend a tab in every line of diff output echo -e "1\t2\n3\n4" > myfile1 ## create some files echo -e "1 2\n5\n4" > myfile2 diff -t myfile1 myfile2 ## expands tab in space diff -T myfile1 myfile2 ## prepends tab to everyline diff myfile1 myfile2 ## normal output |
You can use diff –tabsize=NUM option to tab stops every NUM (default 8) print columns.
1 2 3 4 5 6 |
## Control the tab size in diff output echo -e "1\t\t2" > myfile1 ## create some files echo -e "1 2" > myfile2 ## displays default tab size diff --tabsize=4 myfile1 myfile2 ## displays tab size as 4 |
You can use diff -l, or –paginate options to pass output through ‘pr’ to paginate it.
1 2 3 4 5 6 |
## Pass output through 'pr' to paginate it. echo -e "1\n2\n3" > myfile1 ## create some files echo -e "1\n2" > myfile2 ## normal output diff -l myfile1 myfile2 ## paginate the output |
You can use diff command to compare the contents of directories.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
## compare contents of directories mkdir mydir{1,2} ## create some files and directories echo "hello" > mydir1/myfile1 echo "world" > mydir2/myfile2 echo "linux" > mydir2/myfile3 diff mydir1/ mydir2/ ## compare the contents of directories ## returns ## Only in mydir1/: myfile1 ## Only in mydir2/: myfile2 ## Only in mydir2/: myfile3 rm -r my* |
You can use diff -r or –recursive options to recursively compare any subdirectories found.
1 2 3 4 5 6 7 8 9 10 11 12 |
## compare contents of directories recursively mkdir -p mydir{1,2}/mydir3 ## create some files and directories echo "hello" > mydir1/myfile1 echo "world" > mydir2/myfile2 echo "linux" > mydir1/mydir3/myfile3 echo "cloud" > mydir2/mydir3/myfile4 diff mydir1/ mydir2/ ## does not compares recursively diff -r mydir1/ mydir2/ ## compares recursively rm -r my* |
You can use diff –no-dereference option to not follow symbolic links. The default behavior is to follow a symbolic link.
1 2 3 4 5 6 7 8 9 10 11 |
## do not follow symbolic links mkdir mydir1 ## create some files, directories and symbolic link echo "hello" > mydir1/myfile1 echo "world" > myfile2 ln -s mydir1/myfile1 mylink1 diff --no-dereference mylink1 myfile2 ## does not follow symbolic link diff mylink1 myfile2 ## follows symbolic link (default) rm -r my* |
You can use diff -N or –new-file options to treat absent files as empty.
1 2 3 4 5 6 |
## treat absent files as empty during comparison echo "hello" > myfile1 ## create a file diff myfile1 myfile2 ## error, No such file or directory diff -N myfile1 myfile2 ## treats myfile2 as empty |
You can use diff –unidirectional-new-file option to treat absent first files as empty.
1 2 3 4 5 6 7 8 9 10 11 |
## treat absent first files as empty, rest will be searched and compared. mkdir mydir{1,2} ## create some files and directories echo "hello" > mydir1/myfile1 echo "world" > mydir2/myfile2 echo "cloud" > mydir2/myfile3 diff mydir2 mydir1 ## normal output diff --unidirectional-new-file mydir2 mydir1 ## treats absent first files as empty rm -r my* |
You can use diff –ignore-file-name-case option to ignore case when comparing file names.
1 2 3 4 5 6 7 8 9 10 |
## ignore case when comparing file names mkdir mydir{1,2} ## create some files and directories echo "hello" > mydir1/myfile1 echo "HELLO" > mydir2/MYFILE1 diff mydir1 mydir2 ## treats myfile1 and MYFILE1 as different files diff --ignore-file-name-case mydir1 mydir2 ## myfile1 and MYFILE1 are treated as same file rm -r my* |
You can use diff –no-ignore-file-name-case option to consider case (default behavior) when comparing file names. I am not aware of why this option exists since it’s the default behavior of diff. If you have some ideas, please write in the comment section.
1 2 3 4 5 6 7 8 9 10 |
## consider case (default behaviour) when comparing file names. mkdir mydir{1,2} ## create some files and directories echo "hello" > mydir1/myfile1 echo "HELLO" > mydir2/MYFILE1 diff mydir1 mydir2 ## both returns the same output diff --no-ignore-file-name-case mydir1 mydir2 rm -r my* |
You can use diff -x or –exclude=PATTERN options to exclude files that match PATTERN.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
## exclude files that match PATTERN mkdir mydir{1,2} ## create some files and directories echo "hello" > mydir1/myfile1 echo "linux" > mydir1/file1 echo "world" > mydir2/myfile1 echo "cloud" > mydir2/file1 diff mydir1 mydir2 ## normal output, all are compared diff --exclude="my*" mydir1 mydir2 ## compares only file1 diff --exclude="file*" mydir1 mydir2 ## compares only myfile1 rm -r my* |
You can use diff -X or –exclude-from=FILE options to exclude files that match any pattern in FILE.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
## exclude files that match any pattern 'in' FILE mkdir mydir{1,2} ## create some files and directories echo "hello" > mydir1/myfile1 echo "linux" > mydir1/file1 echo "world" > mydir2/myfile1 echo "cloud" > mydir2/file1 echo "my*" > myfile diff mydir1 mydir2 ## normal output, all are compared diff --exclude-from=myfile mydir1 mydir2 ## excludes myfile1 rm -r my* |
You can use diff -S or –starting-file=FILE options to start with FILE when comparing directories.
1 2 3 4 5 6 7 8 9 10 11 12 |
## Start with a specific file when comparing mkdir mydir{1,2} ## create some files and directories echo "hello" > mydir1/one echo "linux" > mydir1/two echo "world" > mydir2/one echo "cloud" > mydir2/two diff mydir1 mydir2 ## normal output, all are compared diff --starting-file=two mydir1 mydir2 ## file two is compared rm -r my* |
You can use diff –from-file=FILE1 option to compare FILE1 to all operands; FILE1 can be a directory.
1 2 3 4 5 6 7 8 9 10 11 |
## compare FILE1 to all operands echo "hello" > myfile1 ## create some files echo "world" > myfile2 echo "cloud" > myfile3 echo "linux" > myfile4 ## myfile1 is compared with rest of the files diff --from-file=myfile1 myfile2 myfile3 myfile4 rm -r my* |
You can use diff –to-file=FILE2 option to compare all operands to FILE2; FILE2 can be a directory.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
## compare all operands to FILE2 echo "hello" > myfile1 ## create some files echo "world" > myfile2 echo "cloud" > myfile3 echo "linux" > myfile4 ## rest of the files are compared with myfile1 diff --to-file=myfile1 myfile2 myfile3 myfile4 ## myfile1 is compared with rest of the files diff --from-file=myfile1 myfile2 myfile3 myfile4 rm -r my* |
You can use diff -i or –ignore-case options to ignore case differences in file contents.
1 2 3 4 5 6 7 |
## ignore case differences in file contents echo -e "one\nTWO\nthree" > myfile1 ## create some files echo -e "one\ntwo\nthree" > myfile2 diff myfile1 myfile2 ## normal comparison diff -i myfile1 myfile2 ## ignore case in file contents |
You can use diff -E or –ignore-tab-expansion options to ignore changes due to tab expansion.
1 2 3 4 5 6 7 8 9 10 11 |
## Ignore changes due to tab expansion tabs 4 ## set tab length and create some files echo -e "1\n2\t3\n4" > myfile1 tabs 6 echo -e "1\n2\t3\n4" > myfile2 diff myfile1 myfile2 ## normal output diff -E myfile1 myfile2 ## ignore changes due to tab expansion tabs 4 |
You can use diff -b or –ignore-space-change options to ignore changes in the amount of white space.
1 2 3 4 5 6 7 |
## ignore changes in the amount of white space echo "hello world" > myfile1 ## create some files echo "hello world" > myfile2 diff myfile1 myfile2 ## normal output diff -b myfile1 myfile2 ## ignore changes in the amount of white space |
You can use diff -w or –ignore-all-space options to ignore all white space.
1 2 3 4 5 6 7 8 |
## ignore all white space echo -e " hello\n world" > myfile1 ## create some files echo -e "hello\nworld " > myfile2 diff myfile1 myfile2 ## normal output diff -b myfile1 myfile2 ## ignore changes in the amount of white space diff -w myfile1 myfile2 ## ignore all white space |
You can use diff -B or –ignore-blank-lines options to ignore changes where lines are all blank.
1 2 3 4 5 6 7 |
## ignore changes where lines are all blank echo -e "hello\n\nworld" > myfile1 ## create some files echo -e "hello\nworld" > myfile2 diff myfile1 myfile2 ## blank lines are also compared diff -B myfile1 myfile2 ## ignore changes where lines are all blank |
You can use diff -I RE or –ignore-matching-lines=RE options to ignore changes where all lines match RE. Ignore changes that just insert or delete lines that match RE.
1 2 3 4 5 6 7 8 9 |
## ignore changes where all lines match regular expression echo -e "hello\nworld" > myfile1 ## create some files echo -e "hello\nworld\nwelcome" > myfile2 diff myfile1 myfile2 ## all are compared diff --ignore-matching-lines="welcome" myfile1 myfile2 ## welcome is ignored rm -r my* |
Hope you have enjoyed this article. There are tons of options supported by diff command and due to time limitation, all option examples are not given in this blog post. If you want, you can give other options example in the comment section and we will collate all and include in this blog to make it the complete reference for Linux diff command.
In the next blog post, we will discuss more command in Linix.