compare two files and save the difference in linux - linux

I like to compare two text files and save the difference under linux.
I know there are tools like kdiff, diff vimdiff etc. but my expectation are as follows.
Output should be in a separate file
The difference should be quoted with colours, ex: delete line in red and added line in green something like that
It should ignore space differences
It should be an opensource tool

use tkdiff4 -w file-name1 file-name2
It fulfills all your requirements. Specific color might be an issue.

try colordiff and man diff for options for ignoring whitespace etc

Like,
#!/bin/bash
wdiff -w "\e[31m" -x "\e[0m" -y "\e[32m" -z "\e[0m" "$#";
replace \e by, well, the ASCII character with value 0x1A. Put the two commands into some file, and run it using redirection.

Save the changes to a file:
diff -Nur originalfile newfile > patchfile
Use the difference file to change the origin file:
patch originfile patchfile
I think this is the easiest way to save the changes and reload the changes.
By the way, you can use this command the create an update-package.

Related

Is it possible to display a file's contents and delete that file in the same command?

I'm trying to display the output of an AWS lambda that is being captured in a temporary text file, and I want to remove that file as I display its contents. Right now I'm doing:
... && cat output.json && rm output.json
Is there a clever way to combine those last two commands into one command? My goal is to make the full combined command string as short as possible.
For cases where
it is possible to control the name of the temporary text file.
If file is not used by other code
Possible to pass "/dev/stdout" as the.name of the output
Regarding portability: see stack exchange how portable ... /dev/stdout
POSIX 7 says they are extensions.
Base Definitions,
Section 2.1.1 Requirements:
The system may provide non-standard extensions. These are features not required by POSIX.1-2008 and may include, but are not limited to:
[...]
• Additional character special files with special properties (for example,  /dev/stdin, /dev/stdout,  and  /dev/stderr)
Using the mandatory supported /dev/tty will force output into “current” terminal, making it impossible to pipe the output of the whole command into different program (or log file), or to use the program when there is no connected terminals (cron job, or other automation tools)
No, you cannot easily remove the lines of a file while displaying them. It would be highly inefficient as it would require removing characters from the beginning of a file each time you read a line. Current filesystems are pretty good at truncating lines at the end of a file, but not at the beginning.
A simple but extremely slow method would look like this:
while [ -s output.json ]
do
head -1 output.json
sed -i 1d output.json
done
While this algorithm is plain and simple, you should know that each time you remove the first line with sed -i 1d it will copy the whole content of the file but the first line into a temporary file, resulting in approximately 0.5*n² lines written in total (where n is the number of lines in your file).
In theory you could avoid this by do something like that:
while [ -s output.json ]
do
line=$(head -1 output.json)
printf -- '%s\n' "$line"
fallocate -c -o 0 -l $((${#len}+1)) output.json
done
But this does not account for variable newline characters (namely DOS-formatted newlines) and fallocate does not always work on xfs, among other issues.
Since you are trying to consume a file alongside its creation without leaving a trace of its existence on disk, you are essentially asking for a pipe functionality. In my opinion you should look into how your output.json file is produced and hopefully you can pipe it to a script of your own.

Manually merge two files using diff

I'd like to merge two files by doing the following:
Output the diff of the two files into a temp file and
Manually select the lines I want to copy/save.
The problem here is that diff -u only gives me a file lines of context, while I want to output the entire file in a unified format.
Is there any way diff can do this?
One option that might fit the bill for you,
sdiff : side-by-side diff of files.
sdiff -o merged.file left.file right.file
Once there, it will prompt you with what lines you want to keep from which file. Hit ? and then enter for a little help. Also man sdiff with the detailed goods.
(In my distro, these come packaged in the "diffutils" package [fedora,centos])
If you need to automate the process, you might want to try the util merge, which will mark conflicts in the files. However, that might put you back at square one.
"I want to output the entire file in a unified format. Is there any way diff can do this?"
Yes.
diff -U 9999999 file1.txt file2.txt > diff.txt
This should work, provided your files are less than 10 million lines long.
You can merge/combine the two files with diff using --
diff --line-format %L file1 file2
The easy answer is to use the -D flag to merge the files and surround the differences with C style #ifdef statements.
From the documentation:
-D NAME --ifdef=NAME
Output merged file to show `#ifdef NAME' diffs.
You can use it as follows:
$ diff -D NEWSTUFF file1 file2 > merged_file
I usually then just open the merged file in an editor and resolve the merge conflicts by hand.
You also can use options to output an ed script, etc.
If you are an emacs user, you can do this directly in emacs using the "emerge" tool:
https://www.gnu.org/software/emacs/manual/html_node/emacs/Emerge.html
Issuing M-x emerge-files will open an interactive prompt with a view of files A, B, and the merged file to allow choosing text that differs between files A & B, inserting part of A into B, and more.

How to use to diff to C++ source files and ignore the line space and comments

I have to C++ source files and I want to see the difference between the two files. But I don't want to see the diff between the comments.
Please advise.
Many thanks.
One way would be to use the pre-processor to remove the comments and pass this into diff using process substitution...
diff -uwB <(g++ -E left.cpp) <(g++ -E right.cpp)
Of course this will pull in files that you #include and expand your #define macros, too. If they haven't changed, this should be quite readable.
The switches I have passed to diff are:
-w --ignore-all-space Ignore all white space.
-B --ignore-blank-lines Ignore changes whose lines are all blank.
-u -U NUM --unified[=NUM] Output NUM (default 3) lines of unified context.

help - change diff symbol "<", "|" or ">" to a desired one?

diff -w command is used to create a side by side comparison diff file (instead of parallel)
i then view them using vi via ssh terminal
the changes are indicated by either "<" or "|" or ">"
Since the file i am viewing is a source code, navigating to changes alone
using above symbols is difficult since they are also in C source code.
How can i change these default symbols to desired ones ?
Kindly help. Thanks.
Instead of viewing the output of diff -w in vim, you can use vim's built-in diff:
vim -d file1 file2
This opens vim in a vertical split with both files open, and diff markings in the code. This is what it looks like:
And it works in a terminal too:
You can find a short tutorial here
According to my version of diff (2.8.1 from the GNU diffutils by the FSF) -w is used to change the width of the output; The -y parameter outputs side by side comparison. In combination, the two show no further effect than the -y parameter used alone, which means you may have an alias in your terminal profile or in the global terminal profile that aliases diff to diff -y.
I say all this because all options to change the symbols ("<", "|", and ">") conflict with the -y option. If you can live without side-by-side, you have the option of two other included output styles or defining your own. The two output styles are -c (context) and -u (unified). (For more information on what they do see the diff Wikipedia page. For more information on the options see the diff man page.)
A more in depth fix would be to use the following options:
diff --old-group-format="(deleted)---" \
--new-group-format="(added)---" \
--changed-group-format="(updated)---" \
--unchanged-group-format="(nodiff)---" \
old_file.c new_file.c
Now the old file's lines that are not present in the new file are represented by (deleted)---
The new file's lines that are not present in the old file are represented by (added)---
Lines that have been changed are represented by (updated)---
Lines common to both files are represented by (nodiff)---
Since you seem to do this often enough, you have the option of making it an alias in your terminal profile or writing a small shell script to handle it. For more options, see the manual's section on options and specifically see the section on line group formats for information on what you can put between the quotes in the format definitions.
Of course, if you must have side-by-side, try Nathan Fellman's idea above. Otherwise, there's the option of using a dedicated GUI tool for it such as Kompare.

Is there a script that would allow me to edit multiple files as if they are one file in VIM?

I prefer to edit in one large file rather than many independent files, but due to limitations in languages, source control, and the preference of team mates I need to output to many files.
What I'm looking for would recurse through all the files in a source directory and generate a single file to edit in VIM, with special file seperator markers. On save it would save the the changes to the correct file(s) ideally in a smart manner, based only on changes made.
Does something like this exist?
shar
Well, you could use shar(1), but it puts an X in front of each line that you will probably find annoying. (Shar came with my Mac but on my Linux systems you need to add a package.)
Shar is just, itself, a short shell script, so you could modify it easily enough to work without the X.
You might try copying /usr/bin/shar to /tmp and applying this diff with patch(1).
--- /usr/bin/shar 2009-07-13 22:26:18.000000000 -0700
+++ /tmp/shar2 2010-12-24 19:05:34.000000000 -0800
## -65,8 +65,8 ##
echo "mkdir -p $i > /dev/null 2>&1"
else
echo "echo x - $i"
- echo "sed 's/^X//' >$i << 'END-of-$i'"
- sed 's/^/X/' $i
+ echo "cat >$i << 'END-of-$i'"
+ cat $i
echo "END-of-$i"
fi
done
It reminds me of vimballs format. However, it's meant to expand files into the user runtimepath directory.
In other words, you can list all the files you want join and apply :MkVimBall (here is an example).
Then, for the extraction, you will have to momentarily (i.e. save and restore its value after the extraction) set &runtimepath to the root directory of your project before extracting with :so %.
You'll also have to play with various options like the &filetype, etc.
It's a dirty hack, but well ... it shall do the job.
Instead of dumping several files into one, processing this one and then separating stuff apart again, you could use bufdo or windo to repeat a command on all opened buffers: open the buffers to be processed, then cast the bufdo command and it will work on every opened file: http://vimdoc.sourceforge.net/htmldoc/windows.html#list-repeat

Resources