#!/bin/bash
same='-' #unchanged
up='△' #exists in first line, but not in second
down='▽' #exists in second line, but not in first
reset=''
reset=$'\e[0m'
same=$reset
up=$reset$'\e[1m\e[7m'
down=$reset$'\e[1m\e[7m\e[31m'
timeout=1
if [[ "$1" != '' ]]
then
paste -d'\n' "$1" "$2" | "$0"
exit
fi
function demo {
"$0" <<EOF
Paris in the spring
Paris in the the spring
A cat on a hot tin roof.
a cant on a hot in roof
the quikc brown box jupps ober the laze dogs
The quickbrown fox jumps over the lazy dogs
EOF
}
# Change \x20 to \x02 to simplify parsing diff's output,
#+ then change \x02 back to \x20 for the final output.
# Change \x09 to \x01 to simplify parsing diff's output,
#+ then change \x01 into → U+1F143 (Squared Latin Capital Letter T)
function input {
sed \
-e "s/\x09/\x01/g" \
-e "s/\x20/\x02/g" \
-e "s/\(.\)/\1\n/g"
}
function output {
sed -n \
-e "s/\x01/→/g" \
-e "s/\x02/ /g" \
-e "s/^\(.\) *\x3C$/\1 \x3C /g" \
-e "s/\(.\) *\(.\) \(.\)$/\1\2\3/p"
}
ifs="$IFS"
IFS=$'\n'
demo=true
while IFS= read -t "$timeout" -r a
do
demo=false
IFS= read -t "$timeout" -r b
if [[ $? -ne 0 ]]
then
echo 'No corresponding line to compare with' > /dev/stderr
exit 1
fi
diff --text -yt -W 19 \
<(echo "$a" | input) \
<(echo "$b" | input) \
| \
output | \
{
type=''
buf=''
while read -r line
do
if [[ $"${line:1:1}" != $type"$type" ]]
then
if [[ $type"$type" = '|' ]]
then
type='>'
echo -n "$down$buf"
buf=''
fi
if [[ $"${line:1:1}" != $type"$type" ]]
then
type=$type="${line:1:1}"
echo -n $type"$type" \
| sed \
-e "s/[<|]/$up/" \
-e "s/>/$down/" \
-e "s/ /$same/"
fi
fi
case $type"$type" in
'|')
buf=$buf$buf="$buf${line:2:1}"
echo -n $"${line:0:1}"
;;
'>')
echo -n $"${line:2:1}"
;;
*)
echo -n $"${line:0:1}"
;;
esac
done
if [[ $type"$type" = '|' ]]
then
echo -n "$down$buf"
fi
}
echo -e "$reset"
done
IFS="$ifs"
if $demo
then
demo
fi
#!/bin/bash
same='-' #unchanged
up='△' #exists in first line, but not in second
down='▽' #exists in second line, but not in first
reset=''
reset=$'\e[0m'
same=$reset
up=$reset$'\e[1m\e[7m'
down=$reset$'\e[1m\e[7m\e[31m'
timeout=1
if [[ "$1" != '' ]]
then
paste -d'\n' "$1" "$2" | "$0"
exit
fi
function demo {
"$0" <<EOF
Paris in the spring
Paris in the the spring
A cat on a hot tin roof.
a cant on a hot in roof
the quikc brown box jupps ober the laze dogs
The quickbrown fox jumps over the lazy dogs
EOF
}
# Change \x20 to \x02 to simplify parsing diff's output,
#+ then change \x02 back to \x20 for the final output.
# Change \x09 to \x01 to simplify parsing diff's output,
#+ then change \x01 into → U+1F143 (Squared Latin Capital Letter T)
function input {
sed \
-e "s/\x09/\x01/g" \
-e "s/\x20/\x02/g" \
-e "s/\(.\)/\1\n/g"
}
function output {
sed -n \
-e "s/\x01/→/g" \
-e "s/\x02/ /g" \
-e "s/^\(.\) *\x3C$/\1 \x3C /g" \
-e "s/\(.\) *\(.\) \(.\)$/\1\2\3/p"
}
ifs="$IFS"
IFS=$'\n'
demo=true
while IFS= read -t "$timeout" -r a
do
demo=false
IFS= read -t "$timeout" -r b
if [[ $? -ne 0 ]]
then
echo 'No corresponding line to compare with' > /dev/stderr
exit 1
fi
diff --text -yt -W 19 \
<(echo "$a" | input) \
<(echo "$b" | input) \
| \
output | \
{
type=''
buf=''
while read -r line
do
if [[ ${line:1:1} != $type ]]
then
if [[ $type = '|' ]]
then
type='>'
echo -n "$down$buf"
buf=''
fi
if [[ ${line:1:1} != $type ]]
then
type=${line:1:1}
echo -n $type \
| sed \
-e "s/[<|]/$up/" \
-e "s/>/$down/" \
-e "s/ /$same/"
fi
fi
case $type in
'|')
buf=$buf${line:2:1}
echo -n ${line:0:1}
;;
'>')
echo -n ${line:2:1}
;;
*)
echo -n ${line:0:1}
;;
esac
done
if [[ $type = '|' ]]
then
echo -n "$down$buf"
fi
}
echo -e "$reset"
done
IFS="$ifs"
if $demo
then
demo
fi
#!/bin/bash
same='-' #unchanged
up='△' #exists in first line, but not in second
down='▽' #exists in second line, but not in first
reset=''
reset=$'\e[0m'
same=$reset
up=$reset$'\e[1m\e[7m'
down=$reset$'\e[1m\e[7m\e[31m'
timeout=1
if [[ "$1" != '' ]]
then
paste -d'\n' "$1" "$2" | "$0"
exit
fi
function demo {
"$0" <<EOF
Paris in the spring
Paris in the the spring
A cat on a hot tin roof.
a cant on a hot in roof
the quikc brown box jupps ober the laze dogs
The quickbrown fox jumps over the lazy dogs
EOF
}
# Change \x20 to \x02 to simplify parsing diff's output,
#+ then change \x02 back to \x20 for the final output.
# Change \x09 to \x01 to simplify parsing diff's output,
#+ then change \x01 into → U+1F143 (Squared Latin Capital Letter T)
function input {
sed \
-e "s/\x09/\x01/g" \
-e "s/\x20/\x02/g" \
-e "s/\(.\)/\1\n/g"
}
function output {
sed -n \
-e "s/\x01/→/g" \
-e "s/\x02/ /g" \
-e "s/^\(.\) *\x3C$/\1 \x3C /g" \
-e "s/\(.\) *\(.\) \(.\)$/\1\2\3/p"
}
ifs="$IFS"
IFS=$'\n'
demo=true
while IFS= read -t "$timeout" -r a
do
demo=false
IFS= read -t "$timeout" -r b
if [[ $? -ne 0 ]]
then
echo 'No corresponding line to compare with' > /dev/stderr
exit 1
fi
diff --text -yt -W 19 \
<(echo "$a" | input) \
<(echo "$b" | input) \
| \
output | \
{
type=''
buf=''
while read -r line
do
if [[ "${line:1:1}" != "$type" ]]
then
if [[ "$type" = '|' ]]
then
type='>'
echo -n "$down$buf"
buf=''
fi
if [[ "${line:1:1}" != "$type" ]]
then
type="${line:1:1}"
echo -n "$type" \
| sed \
-e "s/[<|]/$up/" \
-e "s/>/$down/" \
-e "s/ /$same/"
fi
fi
case "$type" in
'|')
buf="$buf${line:2:1}"
echo -n "${line:0:1}"
;;
'>')
echo -n "${line:2:1}"
;;
*)
echo -n "${line:0:1}"
;;
esac
done
if [[ "$type" = '|' ]]
then
echo -n "$down$buf"
fi
}
echo -e "$reset"
done
IFS="$ifs"
if $demo
then
demo
fi
#!/bin/bash
same='-' #unchanged
up='△' #exists in first line, but not in second
down='▽' #exists in second line, but not in first
reset=''
same=$'\e[0m'reset=$'\e[0m'
up=$'\e[1m\e[7m'same=$reset
down=$'\e[1m\e[7m\e[31m'up=$reset$'\e[1m\e[7m'
reset="$same"down=$reset$'\e[1m\e[7m\e[31m'
timeout=1
if [[ "$1" != '' ]]
then
paste -d'\n' "$1" "$2" | "$0"
exit
fi
function demo {
"$0" <<EOF
Paris in the spring
Paris in the the spring
A cat on a hot tin roof.
a cant on a hot in roof
the quikc brown box jupps ober the laze dogs
The quickbrown fox jumps over the lazy dogs
EOF
}
# Change \x20 to \x02 to simplify parsing diff's output,
#+ then change \x02 back to \x20 for the final output.
# Change \x09 to \x01 to simplify parsing diff's output,
#+ then change \x01 into → U+1F143 (symbol typically used to indicate tab characters when showing formattingSquared marksLatin inCapital wordLetter editorsT)
function input {
sed \
-e "s/\x09/\x01/g" \
-e "s/\x20/\x02/g" \
-e "s/\(.\)/\1\n/g"
}
function output {
sed -n \
-e "s/\x01/→/g" \
-e "s/\x02/ /g" \
-e "s/^\(.\) *\x3C$/\1 \x3C /g" \
-e "s/\(.\) *\(.\) \(.\)$/\1\2\3/p"
}
ifs="$IFS"
IFS=$'\n'
set -f
demo=true
while IFS= read -t 1"$timeout" -r a
do
demo=false
IFS= read -t 1"$timeout" -r b
if [[ $? -ne 0 ]]
then
echo 'No corresponding line to compare with' > /dev/stderr
exit 1
fi
diff --text -yt -W 19 \
<(echo "$a" | input) \
<(echo "$b" | input) \
| \
output | \
{
type=''
buf=''
while read -r line
do
if [[ ${line:1:1} != $type ]]
then
if [[ $type = '|' ]]
then
type='>'
echo -n "$down$buf"
buf=''
fi
if [[ ${line:1:1} != $type ]]
then
type=${line:1:1}
echo -n $type \
| sed \
-e "s/[<|]/$up/" \
-e "s/>/$down/" \
-e "s/ /$same/"
fi
fi
case $type in
'|')
buf=$buf${line:2:1}
echo -n ${line:0:1}
;;
'>')
echo -n ${line:2:1}
;;
*)
echo -n ${line:0:1}
;;
esac
done
if [[ $type = '|' ]]
then
echo -n "$down$buf"
fi
}
echo -e "$reset"
done
IFS="$ifs"
set +f
if $demo
then
demo
fi
#!/bin/bash
same='-' #unchanged
up='△' #exists in first line, but not in second
down='▽' #exists in second line, but not in first
reset=''
same=$'\e[0m'
up=$'\e[1m\e[7m'
down=$'\e[1m\e[7m\e[31m'
reset="$same"
if [[ "$1" != '' ]]
then
paste -d'\n' "$1" "$2" | "$0"
exit
fi
function demo {
"$0" <<EOF
Paris in the spring
Paris in the the spring
A cat on a hot tin roof.
a cant on a hot in roof
the quikc brown box jupps ober the laze dogs
The quickbrown fox jumps over the lazy dogs
EOF
}
# Change \x20 to \x02 to simplify parsing diff's output,
#+ then change \x02 back to \x20 for the final output.
# Change \x09 to \x01 to simplify parsing diff's output,
#+ then change \x01 into → U+1F143 (symbol typically used to indicate tab characters when showing formatting marks in word editors)
function input {
sed \
-e "s/\x09/\x01/g" \
-e "s/\x20/\x02/g" \
-e "s/\(.\)/\1\n/g"
}
function output {
sed -n \
-e "s/\x01/→/g" \
-e "s/\x02/ /g" \
-e "s/^\(.\) *\x3C$/\1 \x3C /g" \
-e "s/\(.\) *\(.\) \(.\)$/\1\2\3/p"
}
ifs="$IFS"
IFS=$'\n'
set -f
demo=true
while IFS= read -t 1 -r a
do
demo=false
IFS= read -t 1 -r b
if [[ $? -ne 0 ]]
then
echo 'No corresponding line to compare with' > /dev/stderr
exit 1
fi
diff --text -yt -W 19 \
<(echo "$a" | input) \
<(echo "$b" | input) \
| \
output | \
{
type=''
buf=''
while read -r line
do
if [[ ${line:1:1} != $type ]]
then
if [[ $type = '|' ]]
then
type='>'
echo -n "$down$buf"
buf=''
fi
if [[ ${line:1:1} != $type ]]
then
type=${line:1:1}
echo -n $type \
| sed \
-e "s/[<|]/$up/" \
-e "s/>/$down/" \
-e "s/ /$same/"
fi
fi
case $type in
'|')
buf=$buf${line:2:1}
echo -n ${line:0:1}
;;
'>')
echo -n ${line:2:1}
;;
*)
echo -n ${line:0:1}
;;
esac
done
if [[ $type = '|' ]]
then
echo -n "$down$buf"
fi
}
echo -e "$reset"
done
IFS="$ifs"
set +f
if $demo
then
demo
fi
#!/bin/bash
same='-' #unchanged
up='△' #exists in first line, but not in second
down='▽' #exists in second line, but not in first
reset=''
reset=$'\e[0m'
same=$reset
up=$reset$'\e[1m\e[7m'
down=$reset$'\e[1m\e[7m\e[31m'
timeout=1
if [[ "$1" != '' ]]
then
paste -d'\n' "$1" "$2" | "$0"
exit
fi
function demo {
"$0" <<EOF
Paris in the spring
Paris in the the spring
A cat on a hot tin roof.
a cant on a hot in roof
the quikc brown box jupps ober the laze dogs
The quickbrown fox jumps over the lazy dogs
EOF
}
# Change \x20 to \x02 to simplify parsing diff's output,
#+ then change \x02 back to \x20 for the final output.
# Change \x09 to \x01 to simplify parsing diff's output,
#+ then change \x01 into → U+1F143 (Squared Latin Capital Letter T)
function input {
sed \
-e "s/\x09/\x01/g" \
-e "s/\x20/\x02/g" \
-e "s/\(.\)/\1\n/g"
}
function output {
sed -n \
-e "s/\x01/→/g" \
-e "s/\x02/ /g" \
-e "s/^\(.\) *\x3C$/\1 \x3C /g" \
-e "s/\(.\) *\(.\) \(.\)$/\1\2\3/p"
}
ifs="$IFS"
IFS=$'\n'
demo=true
while IFS= read -t "$timeout" -r a
do
demo=false
IFS= read -t "$timeout" -r b
if [[ $? -ne 0 ]]
then
echo 'No corresponding line to compare with' > /dev/stderr
exit 1
fi
diff --text -yt -W 19 \
<(echo "$a" | input) \
<(echo "$b" | input) \
| \
output | \
{
type=''
buf=''
while read -r line
do
if [[ ${line:1:1} != $type ]]
then
if [[ $type = '|' ]]
then
type='>'
echo -n "$down$buf"
buf=''
fi
if [[ ${line:1:1} != $type ]]
then
type=${line:1:1}
echo -n $type \
| sed \
-e "s/[<|]/$up/" \
-e "s/>/$down/" \
-e "s/ /$same/"
fi
fi
case $type in
'|')
buf=$buf${line:2:1}
echo -n ${line:0:1}
;;
'>')
echo -n ${line:2:1}
;;
*)
echo -n ${line:0:1}
;;
esac
done
if [[ $type = '|' ]]
then
echo -n "$down$buf"
fi
}
echo -e "$reset"
done
IFS="$ifs"
if $demo
then
demo
fi
- It only prints every line once, using colour to show you the differences.
- It doesn't write any temp files, piping everything instead.
- You can provide two filenames and it'll compare the corresponding lines in each file.
./hairOfTheDiff.sh file1.shtxt file2.shtxt - Otherwise, if you use the original format (a single file with every second line needing to be compared to the one before) you may now simply pipe it in, no file needs to exist to be read. Take a look at take a look at
demoin the sourcedemoin the source; this may open the door to fancy piping in order to not need files for two separate inputs too, usingpasteand multiple file-descriptors.
#!/bin/bash
same='-' #unchanged
up='△' #exists in first line, but not in second
down='▽' #exists in second line, but not in first
reset=''
same=$'\e[0m'
up=$'\e[1m\e[7m'
down=$'\e[1m\e[7m\e[31m'
reset="$same"
if [[ "$1" != '' ]]
then
paste -d'\n' "$1" "$2" | "$0"
exit
fi
function demo {
"$0" <<EOF
Paris in the spring
Paris in the the spring
A cat on a hot tin roof.
a cant on a hot in roof
the quikc brown box jupps ober the laze dogs
The quickbrown fox jumps over the lazy dogs
EOF
}
# Change \x20 to \x02 to simplify parsing diff's output,
#+ then change \x02 back to \x20 for the final output.
# Change \x09 to \x01 to simplify parsing diff's output,
#+ then change \x01 into → U+1F143 (symbol typically used to indicate tab characters when showing formatting marks in word editors)
function input {
sed \
-e "s/\x09/\x01/g" \
-e "s/\x20/\x02/g" \
-e "s/\(.\)/\1\n/g"
}
function output {
sed -n \
-e "s/\x01/→/g" \
-e "s/\x02/ /g" \
-e "s/^\(.\) *\x3C$/\1 \x3C /g" \
-e "s/\(.\) *\(.\) \(.\)$/\1\2\3/p"
}
ifs="$IFS"
IFS=$'\n'
set -f
demo=true
while IFS= read -t 1 -r a
do
demo=false
IFS= read -t 1 -r b
if [[ $? -ne 0 ]]
then
echo 'No corresponding line to compare with' > /dev/stderr
exit 1
fi
# Change \x20 to \x02 to simplify parsing diff's output,
#+ then change \x02 back to \x20 for the final output.
# Change \x09 to \x01 to simplify parsing diff's output,
#+ then change \x01 into → U+1F143 (Squared Latin Capital Letter T)
diff --text -yt -W 19 \
<(echo "$a" | input) \
<(echo "$b" | input) \
| \
output | \
{
type=''
buf=''
while read -r line
do
if [[ ${line:1:1} != $type ]]
then
if [[ $type = '|' ]]
then
type='>'
echo -n "$down$buf"
buf=''
fi
if [[ ${line:1:1} != $type ]]
then
type=${line:1:1}
echo -n $type \
| sed \
-e "s/[<|]/$up/" \
-e "s/>/$down/" \
-e "s/ /$same/"
fi
fi
case $type in
'|')
buf=$buf${line:2:1}
echo -n ${line:0:1}
;;
'>')
echo -n ${line:2:1}
;;
*)
echo -n ${line:0:1}
;;
esac
done
if [[ $type = '|' ]]
then
echo -n "$down$buf"
fi
}
echo -e "$reset"
done
IFS="$ifs"
set +f
if $demo
then
demo
fi
- It only prints every line once, using colour to show you the differences.
- It doesn't write any temp files, piping everything instead.
- You can provide two filenames and it'll compare the corresponding lines in each file.
./hairOfTheDiff.sh file1.sh file2.sh - Otherwise, if you use the original format (a single file with every second line needing to be compared to the one before) you may now simply pipe it in, no file needs to exist to be read. take a look at
demoin the source
#!/bin/bash
same='-' #unchanged
up='△' #exists in first line, but not in second
down='▽' #exists in second line, but not in first
reset=''
same=$'\e[0m'
up=$'\e[1m\e[7m'
down=$'\e[1m\e[7m\e[31m'
reset="$same"
if [[ "$1" != '' ]]
then
paste -d'\n' "$1" "$2" | "$0"
exit
fi
function demo {
"$0" <<EOF
Paris in the spring
Paris in the the spring
A cat on a hot tin roof.
a cant on a hot in roof
the quikc brown box jupps ober the laze dogs
The quickbrown fox jumps over the lazy dogs
EOF
}
function input {
sed \
-e "s/\x09/\x01/g" \
-e "s/\x20/\x02/g" \
-e "s/\(.\)/\1\n/g"
}
function output {
sed -n \
-e "s/\x01/→/g" \
-e "s/\x02/ /g" \
-e "s/^\(.\) *\x3C$/\1 \x3C /g" \
-e "s/\(.\) *\(.\) \(.\)$/\1\2\3/p"
}
ifs="$IFS"
IFS=$'\n'
set -f
demo=true
while IFS= read -t 1 -r a
do
demo=false
IFS= read -t 1 -r b
if [[ $? -ne 0 ]]
then
echo 'No corresponding line to compare with' > /dev/stderr
exit 1
fi
# Change \x20 to \x02 to simplify parsing diff's output,
#+ then change \x02 back to \x20 for the final output.
# Change \x09 to \x01 to simplify parsing diff's output,
#+ then change \x01 into → U+1F143 (Squared Latin Capital Letter T)
diff --text -yt -W 19 \
<(echo "$a" | input) \
<(echo "$b" | input) \
| \
output | \
{
type=''
buf=''
while read -r line
do
if [[ ${line:1:1} != $type ]]
then
if [[ $type = '|' ]]
then
type='>'
echo -n "$down$buf"
buf=''
fi
if [[ ${line:1:1} != $type ]]
then
type=${line:1:1}
echo -n $type \
| sed \
-e "s/[<|]/$up/" \
-e "s/>/$down/" \
-e "s/ /$same/"
fi
fi
case $type in
'|')
buf=$buf${line:2:1}
echo -n ${line:0:1}
;;
'>')
echo -n ${line:2:1}
;;
*)
echo -n ${line:0:1}
;;
esac
done
if [[ $type = '|' ]]
then
echo -n "$down$buf"
fi
}
echo -e "$reset"
done
IFS="$ifs"
set +f
if $demo
then
demo
fi
- It only prints every line once, using colour to show you the differences.
- It doesn't write any temp files, piping everything instead.
- You can provide two filenames and it'll compare the corresponding lines in each file.
./hairOfTheDiff.sh file1.txt file2.txt - Otherwise, if you use the original format (a single file with every second line needing to be compared to the one before) you may now simply pipe it in, no file needs to exist to be read. Take a look at
demoin the source; this may open the door to fancy piping in order to not need files for two separate inputs too, usingpasteand multiple file-descriptors.
#!/bin/bash
same='-' #unchanged
up='△' #exists in first line, but not in second
down='▽' #exists in second line, but not in first
reset=''
same=$'\e[0m'
up=$'\e[1m\e[7m'
down=$'\e[1m\e[7m\e[31m'
reset="$same"
if [[ "$1" != '' ]]
then
paste -d'\n' "$1" "$2" | "$0"
exit
fi
function demo {
"$0" <<EOF
Paris in the spring
Paris in the the spring
A cat on a hot tin roof.
a cant on a hot in roof
the quikc brown box jupps ober the laze dogs
The quickbrown fox jumps over the lazy dogs
EOF
}
# Change \x20 to \x02 to simplify parsing diff's output,
#+ then change \x02 back to \x20 for the final output.
# Change \x09 to \x01 to simplify parsing diff's output,
#+ then change \x01 into → U+1F143 (symbol typically used to indicate tab characters when showing formatting marks in word editors)
function input {
sed \
-e "s/\x09/\x01/g" \
-e "s/\x20/\x02/g" \
-e "s/\(.\)/\1\n/g"
}
function output {
sed -n \
-e "s/\x01/→/g" \
-e "s/\x02/ /g" \
-e "s/^\(.\) *\x3C$/\1 \x3C /g" \
-e "s/\(.\) *\(.\) \(.\)$/\1\2\3/p"
}
ifs="$IFS"
IFS=$'\n'
set -f
demo=true
while IFS= read -t 1 -r a
do
demo=false
IFS= read -t 1 -r b
if [[ $? -ne 0 ]]
then
echo 'No corresponding line to compare with' > /dev/stderr
exit 1
fi
diff --text -yt -W 19 \
<(echo "$a" | input) \
<(echo "$b" | input) \
| \
output | \
{
type=''
buf=''
while read -r line
do
if [[ ${line:1:1} != $type ]]
then
if [[ $type = '|' ]]
then
type='>'
echo -n "$down$buf"
buf=''
fi
if [[ ${line:1:1} != $type ]]
then
type=${line:1:1}
echo -n $type \
| sed \
-e "s/[<|]/$up/" \
-e "s/>/$down/" \
-e "s/ /$same/"
fi
fi
case $type in
'|')
buf=$buf${line:2:1}
echo -n ${line:0:1}
;;
'>')
echo -n ${line:2:1}
;;
*)
echo -n ${line:0:1}
;;
esac
done
if [[ $type = '|' ]]
then
echo -n "$down$buf"
fi
}
echo -e "$reset"
done
IFS="$ifs"
set +f
if $demo
then
demo
fi