Creating a diff file when the lines in the input files are slightly different
Linux - GeneralThis Linux forum is for general Linux questions and discussion.
If it is Linux Related and doesn't seem to fit in any other forum then this is the place.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
Creating a diff file when the lines in the input files are slightly different
I've been googling this and trying different options in diff both without success.
I'll be very specific so it's easier to understand. I want to create a single patchfile for this.
In both Fedora and Debian, the /etc/grub.d/10_linux are slightly different, but I would like to create a single patchfile that will work on both distros.
Here's a snippet of the file from Debian:
Code:
prefix=/usr
exec_prefix=${prefix}
bindir=${exec_prefix}/bin
libdir=${exec_prefix}/lib
. ${libdir}/grub/grub-mkconfig_lib
export TEXTDOMAIN=grub
export TEXTDOMAINDIR=${prefix}/share/locale
CLASS="--class gnu-linux --class gnu --class os"
if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then
OS=GNU/Linux
else
OS="${GRUB_DISTRIBUTOR} GNU/Linux"
CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr 'A-Z' 'a-z' | cut -d' ' -f1) ${CLASS}"
fi
# loop-AES arranges things so that /dev/loop/X can be our root device, but
# the initrds that Linux uses don't like that.
And this is from Fedora:
Code:
prefix=/usr
exec_prefix=/usr
bindir=/usr/bin
libdir=/usr/lib
. ${libdir}/grub/grub-mkconfig_lib
export TEXTDOMAIN=grub
export TEXTDOMAINDIR=${prefix}/share/locale
CLASS="--class gnu-linux --class gnu --class os"
if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then
OS=Linux
else
OS="${GRUB_DISTRIBUTOR} Linux"
CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr 'A-Z' 'a-z' | cut -d' ' -f1) ${CLASS}"
fi
# loop-AES arranges things so that /dev/loop/X can be our root device, but
# the initrds that Linux uses don't like that.
I only want to patch the lines shown in red with:
Code:
using_submenu=false
CLASS="--class gnu-linux --class gnu --class os"
if [ "x${GRUB_THEME}" != "x" ] && [ -d "`dirname ${GRUB_THEME}`" ]; then
recovery_icon="`dirname ${GRUB_THEME}`/icons/recovery.png"
fi
if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then
OS=GNU/Linux
else
OS="$(echo ${GRUB_DISTRIBUTOR} | cut -d' ' -f1) $(echo ${GRUB_DISTRIBUTOR_CODENAME} | \
sed 's,^.,\u&,')"
DISTRIBUTOR_CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr 'A-Z' 'a-z' | cut -d' ' -f1) ${CLASS}"
fi
Is it possible to create a single patchfile so users on either distro can apply it successfully?
Yes it is, before the variables use an if statement to check what distro you are using if its deb use debs variables, ifs fedoras then use fedoras variables. That should work for what you are doing.
Last edited by ProtoformX; 04-05-2012 at 12:27 PM.
I think ProtoformX may have misinterpreted your question--maybe not.
It gave me pause to think about it though. I am "thinking out loud" here...
Consider this file as your final, "end-product:"
Code:
. /etc/this_machine_distro
if [ ${THIS_DISTRO} = "RED_HAT" ] ; then
prefix=/usr
exec_prefix=/usr
bindir=/usr/bin
libdir=/usr/lib
else
prefix=/usr
exec_prefix=${prefix}
bindir=${exec_prefix}/bin
libdir=${exec_prefix}/lib
fi
. ${libdir}/grub/grub-mkconfig_lib
export TEXTDOMAIN=grub
export TEXTDOMAINDIR=${prefix}/share/locale
CLASS="--class gnu-linux --class gnu --class os"
if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then
OS=GNU/Linux
else
OS="${GRUB_DISTRIBUTOR} GNU/Linux"
CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr 'A-Z' 'a-z' | cut -d' ' -f1) ${CLASS}"
fi
# loop-AES arranges things so that /dev/loop/X can be our root device, but
# the initrds that Linux uses don't like that.
Create a file named /etc/this_machine_distro. In it, place:
Code:
THIS_DISTRO=RED_HAT
or
Code:
THIS_DISTRO=DEBIAN
as appropriate for the particular machine. You could substitute some other method of determining the distribution--just so long as you can use it in the if statement.
Create your patch file against one of the machines by using an original/start-from copy that does not include any of the variable assignments (e.g. prefix, exec, bindir, and libdir)--rip those lines out entirely.
Try to patch against a test file using patch's '-N' option. With luck, when you try to patch a "real" file (that includes the assignments), patch will assume that those assignments are "previously applied patches" to ignore via the -N option.
Again, thinking out loud... I haven't tried it myself.
EDIT:
I think I got dragged off-track as well. Let me think about it some more. There's something percolating...
Last edited by Dark_Helmet; 04-07-2012 at 08:52 PM.
I would say that your easiest option would be to submit a shell script rather than trying to force it through patch. You could easily plug in a sequence of head/tail/sed commands/awk commands to do what you need.
If you must use patch, then (correct me if I am wrong) your problem is that patch refuses to make changes because the context check fails. The context check fails because of the different variable assignments.
So, again, if you are forced to use patch, you need to do something to make the entire file uniform. That's the idea I was getting at in my earlier reply. You include the variable assignments in an if structure to coax patch into believing part of the patch had already been applied. Therefore, the context check would not fail, the existing variable assignment lines would be considered a previously applied patch, and then the file would be updated with the rest of your needed changes (specifically, replacing the text in red).
Does that make sense? I may try to do some experimentation and let you know what I come up with.
If you must use patch, then (correct me if I am wrong) your problem is that patch refuses to make changes because the context check fails. The context check fails because of the different variable assignments.
Yes, this is exactly the problem. The initial var assignments libdir etc, is not the problem. They are excluded from the patchfile with the -U 3 option because export TEXTDOMAIN=grub, export TEXTDOMAINDIR=${prefix}/share/locale and CLASS="--class gnu-linux --class gnu --class os" are all the same across all distros.
The problem is with the var assignments to be changed. So I was thinking whether I could use some sort of directive in the patchfile so as to take the different variable assignment into account, eg:
Code:
if OS="${GRUB_DISTRIBUTOR} GNU/Linux"; then
- OS="${GRUB_DISTRIBUTOR} GNU/Linux"
elif OS="${GRUB_DISTRIBUTOR} Linux"; then
- OS="${GRUB_DISTRIBUTOR} Linux"; then
fi
+ OS="$(echo ${GRUB_DISTRIBUTOR} | cut -d' ' -f1) $(echo ${GRUB_DISTRIBUTOR_CODENAME} | \
sed 's,^.,\u&,')"
But after further reading and by the logical conclusion of what a diff file is, I realized that was not possible.
After even more reading of the man pages, I thought the -D option (--ifdef) would work, but after several attempts, I realized this option is only for ifdef statements within a C source file.
The whole purpose of the diff file was so that the user would not have to manually edit the files, which meant I did not have to provide detailed instructions on doing so. Note that the above snippets are just part of the patch. Some of the hunks are really quite lengthy. Also, this is just one of the file to be patched, there are about four or five others, so a patchfile is definitely a must.
What I eventually did was to create a different patchfile for each distro but I would still like to know if such a thing is at all possible (for future reference).
Unfortunately, the shortfall with this setup is that any line that matches one of the RE's is ignored unless it falls within a hunk containing other changes that do not match any of the RE's.
I initially thought the default context for a unified patch (3 lines) was the culprit and tried to disable context entirely:
I think ProtoformX may have misinterpreted your question--maybe not.
It gave me pause to think about it though. I am "thinking out loud" here...
Consider this file as your final, "end-product:"
Code:
. /etc/this_machine_distro
if [ ${THIS_DISTRO} = "RED_HAT" ] ; then
prefix=/usr
exec_prefix=/usr
bindir=/usr/bin
libdir=/usr/lib
else
prefix=/usr
exec_prefix=${prefix}
bindir=${exec_prefix}/bin
libdir=${exec_prefix}/lib
fi
. ${libdir}/grub/grub-mkconfig_lib
export TEXTDOMAIN=grub
export TEXTDOMAINDIR=${prefix}/share/locale
CLASS="--class gnu-linux --class gnu --class os"
if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then
OS=GNU/Linux
else
OS="${GRUB_DISTRIBUTOR} GNU/Linux"
CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr 'A-Z' 'a-z' | cut -d' ' -f1) ${CLASS}"
fi
# loop-AES arranges things so that /dev/loop/X can be our root device, but
# the initrds that Linux uses don't like that.
This is the right idea.. I meant to rediff the diff, create a backup of the source file apply the patch to the source file, then edit it using if statements to something like the above to check what distro you are using then diff that from the original backup... now you have a patch file that has code in it to detect distros
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.