Так в основном то, что я хочу сделать, сравнивают два файла с методической точностью столбцом 2. Как я мог выполнить это?
File_1.txt:
User1 US
User2 US
User3 US
File_2.txt:
User1 US
User2 US
User3 NG
Output_File:
User3 has changed
Изучите эти diff
команда. Это - хороший инструмент, и можно считать все об этом путем ввода man diff
в терминал.
команда, которую Вы захотите сделать, diff File_1.txt File_2.txt
, который произведет различие между двумя и должен выглядеть примерно так:
А быстрое примечание по чтению вывода от третьей команды: 'стрелки' (<
и >
) обращаются к тому, что значение строки находится в левом файле (<
) по сравнению с правильным файлом (>
) с левым файлом, являющимся тем, который Вы ввели сначала в командную строку, в этом случае File_1.txt
Дополнительно Вы могли бы заметить, что 4-я команда diff ... | tee Output_File
, это передает результаты по каналу diff
в tee
, который тогда помещает тот вывод в файл, так, чтобы можно было на потом сохранить его, если Вы не хотите просматривать все это на консоли прямо в ту секунду.
Litteraly, придерживающийся вопроса (file1, file2, outputfile с "изменил" сообщение), сценарий ниже работ.
Скопируйте сценарий в пустой файл, сохраните его как compare.py
, сделайте это исполняемым файлом, выполните его командой:
/path/to/compare.py <file1> <file2> <outputfile>
Сценарий:
#!/usr/bin/env python
import sys
file1 = sys.argv[1]; file2 = sys.argv[2]; outfile = sys.argv[3]
def readfile(file):
with open(file) as compare:
return [item.replace("\n", "").split(" ") for item in compare.readlines()]
data1 = readfile(file1); data2 = readfile(file2)
mismatch = [item[0] for item in data1 if not item in data2]
with open(outfile, "wt") as out:
for line in mismatch:
out.write(line+" has changed"+"\n")
С несколькими дополнительными строками можно сделать его или печатью к outputfile, или к терминалу, в зависимости от того, если outputfile определяется:
Распечатать в файл:
/path/to/compare.py <file1> <file2> <outputfile>
Распечатать к окну терминала:
/path/to/compare.py <file1> <file2>
Сценарий:
#!/usr/bin/env python
import sys
file1 = sys.argv[1]; file2 = sys.argv[2]
try:
outfile = sys.argv[3]
except IndexError:
outfile = None
def readfile(file):
with open(file) as compare:
return [item.replace("\n", "").split(" ") for item in compare.readlines()]
data1 = readfile(file1); data2 = readfile(file2)
mismatch = [item[0] for item in data1 if not item in data2]
if outfile != None:
with open(outfile, "wt") as out:
for line in mismatch:
out.write(line+" has changed"+"\n")
else:
for line in mismatch:
print line+" has changed"
Или можно использовать Разность Комбинации
, Комбинация помогает Вам сравнить файлы, каталоги, и версия управляла проектами. Это обеспечивает два - и сравнение с тремя путями и файлов и каталогов, и имеет поддержку многих популярных систем управления версиями.
Установка путем выполнения:
sudo apt-get install meld
Ваш пример:
каталог Compare:
Пример с полным из текста:
FWIW, я скорее как то, что я получаю с бок о бок выводом от разности
diff -y -W 120 File_1.txt File_2.txt
, дал бы что-то как:
User1 US User1 US
User2 US User2 US
User3 US | User3 NG
Meld
действительно большой инструмент. Но можно также использовать diffuse
для визуального сравнения двух файлов:
diffuse file1.txt file2.txt
Простой способ состоит в том, чтобы использовать colordiff
, который ведет себя как diff
, но colorizes его вывод. Это очень полезно для чтения diffs. Используя Ваш пример,
$ colordiff -u File_1.txt File_2.txt
--- File_1.txt 2016-12-24 17:59:17.409490554 -0500
+++ File_2.txt 2016-12-24 18:00:06.666719659 -0500
@@ -1,3 +1,3 @@
User1 US
User2 US
-User3 US
+User3 NG
, где u
опция дает объединенное различное. Это - то, как цветная разность похожа:
Установка colordiff
путем выполнения sudo apt-get install colordiff
.
Можно использовать команду cmp
:
cmp -b "File_1.txt" "File_2.txt"
вывод был бы
a b differ: byte 25, line 3 is 125 U 116 N
, Если нет никакой потребности знать, какие части файлов отличаются, можно использовать контрольную сумму файла. Существует много способов сделать это, с помощью md5sum
или sha256sum
. В основном каждый из них производит строку, к которой файл содержание хеширует. Если эти два файла будут тем же, их хеш совпадет с хорошо. Это часто используется при загрузке программного обеспечения, такого как изображения ISO установки Ubuntu. Они часто используются для проверки целостности загруженного содержания.
Рассматривают сценарий ниже, где можно дать два файла как аргументы, и файл скажет Вам, если они будут тем же или нет.
#!/bin/bash
# Check if both files exist
if ! [ -e "$1" ];
then
printf "%s doesn't exist\n" "$1"
exit 2
elif ! [ -e "$2" ]
then
printf "%s doesn't exist\n" "$2"
exit 2
fi
# Get checksums of eithe file
file1_sha=$( sha256sum "$1" | awk '{print $1}')
file2_sha=$( sha256sum "$2" | awk '{print $1}')
# Compare the checksums
if [ "x$file1_sha" = "x$file2_sha" ]
then
printf "Files %s and %s are the same\n" "$1" "$2"
exit 0
else
printf "Files %s and %s are different\n" "$1" "$2"
exit 1
fi
выполненный Образец:
$ ./compare_files.sh /etc/passwd ./passwd_copy.txt
Files /etc/passwd and ./passwd_copy.txt are the same
$ echo $?
0
$ ./compare_files.sh /etc/passwd /etc/default/grub
Files /etc/passwd and /etc/default/grub are different
$ echo $?
1
, Кроме того, существует comm
команда, которая сравнивает два отсортированных файла и дает вывод в 3 colums: столбец 1 для объектов, уникальных для файла № 1, столбца 2 для объектов, уникальных для файла № 2 и столбца 3 для объектов, существующих в обоих файлах.
Для подавления любого столбца можно использовать переключатели-1,-2, и-3. Используя-3 покажет строки, которые отличаются.
Bellow Вы видите снимок экрана команды в действии.
существует всего одно требование - файлы должны быть отсортированы для них, чтобы быть сравненными правильно. sort
команда может использоваться с этой целью. Bellow является другим снимком экрана, где файлы отсортированы и затем сравнены. Строки, запускающиеся слева, принадлежат File_1 только, строки, запускающиеся на столбце 2, принадлежат File_2 [только 1 117]
Установите мерзавца и использование
$ git diff filename1 filename2
И Вы будете произведены в хорошем цветном формате
Установка мерзавца
$ apt-get update
$ apt-get install git-core
Сравнивает пары имя/значение в 2 файлах в формате name value\n
. Записи name
кому: Output_file
если изменено. Требует удара v4 + для ассоциативных массивов.
$ ./colcmp.sh File_1.txt File_2.txt
User3 changed from 'US' to 'NG'
no change: User1,User2
$ cat Output_File
User3 has changed
cmp -s "$1" "$2"
case "$?" in
0)
echo "" > Output_File
echo "files are identical"
;;
1)
echo "" > Output_File
cp "$1" ~/.colcmp.array1.tmp.sh
sed -i -E "s/([^A-Za-z0-9 ])/\\\\\\1/g" ~/.colcmp.array1.tmp.sh
sed -i -E "s/^(.*)$/#\\1/" ~/.colcmp.array1.tmp.sh
sed -i -E "s/^#\\s*(\\S+)\\s+(\\S.*?)\\s*\$/A1\\[\\1\\]=\"\\2\"/" ~/.colcmp.array1.tmp.sh
chmod 755 ~/.colcmp.array1.tmp.sh
declare -A A1
source ~/.colcmp.array1.tmp.sh
cp "$2" ~/.colcmp.array2.tmp.sh
sed -i -E "s/([^A-Za-z0-9 ])/\\\\\\1/g" ~/.colcmp.array2.tmp.sh
sed -i -E "s/^(.*)$/#\\1/" ~/.colcmp.array2.tmp.sh
sed -i -E "s/^#\\s*(\\S+)\\s+(\\S.*?)\\s*\$/A2\\[\\1\\]=\"\\2\"/" ~/.colcmp.array2.tmp.sh
chmod 755 ~/.colcmp.array2.tmp.sh
declare -A A2
source ~/.colcmp.array2.tmp.sh
USERSWHODIDNOTCHANGE=
for i in "${!A1[@]}"; do
if [ "${A2[$i]+x}" = "" ]; then
echo "$i was removed"
echo "$i has changed" > Output_File
fi
done
for i in "${!A2[@]}"; do
if [ "${A1[$i]+x}" = "" ]; then
echo "$i was added as '${A2[$i]}'"
echo "$i has changed" > Output_File
elif [ "${A1[$i]}" != "${A2[$i]}" ]; then
echo "$i changed from '${A1[$i]}' to '${A2[$i]}'"
echo "$i has changed" > Output_File
else
if [ x$USERSWHODIDNOTCHANGE != x ]; then
USERSWHODIDNOTCHANGE=",$USERSWHODIDNOTCHANGE"
fi
USERSWHODIDNOTCHANGE="$i$USERSWHODIDNOTCHANGE"
fi
done
if [ x$USERSWHODIDNOTCHANGE != x ]; then
echo "no change: $USERSWHODIDNOTCHANGE"
fi
;;
*)
echo "error: file not found, access denied, etc..."
echo "usage: ./colcmp.sh File_1.txt File_2.txt"
;;
esac
Разбивка кода и что это означает, в меру моего понимания. Я приветствую редактирования и предложения.
cmp -s "$1" "$2"
case "$?" in
0)
# match
;;
1)
# compare
;;
*)
# error
;;
esac
cmp установит значение $? следующим образом:
Я принял решение использовать случай.. оператор esac к evalute $? потому что значение $? изменения после каждой команды, включая тест ([).
Кроме того, я, возможно, использовал переменную для содержания значения $?:
cmp -s "$1" "$2"
CMPRESULT=$?
if [ $CMPRESULT -eq 0 ]; then
# match
elif [ $CMPRESULT -eq 1 ]; then
# compare
else
# error
fi
Выше делает то же самое как оператор выбора. IDK, который я люблю лучше.
echo "" > Output_File
Выше очищает выходной файл поэтому, если никакие пользователи не изменились, выходной файл будет пуст.
Я делаю эту внутреннюю часть операторы выбора так, чтобы Output_file остался неизменным на ошибке.
cp "$1" ~/.colcmp.arrays.tmp.sh
Выше копий File_1.txt к домашнему dir текущего пользователя.
Например, если бы текущим пользователем является Джон, вышеупомянутое совпало бы с CP "File_1.txt"/home/john/.colcmp.arrays.tmp.sh
В основном я параноик. Я знаю, что эти символы могли иметь особое значение или выполнить внешнюю программу, когда выполнено в сценарии как часть переменного присвоения:
То, что я не знаю, - то, сколько я не знаю об ударе. Я не знаю то, что другие символы могли бы иметь особое значение, но я хочу выйти из них всех с обратной косой чертой:
sed -i -E "s/([^A-Za-z0-9 ])/\\\\\\1/g" ~/.colcmp.array1.tmp.sh
sed может сделать намного больше, чем соответствие образца регулярного выражения. Шаблон сценария "s / (находит) / (замена) /" конкретно выполняет соответствие шаблона.
"s / (находят) / (замена) / (модификаторы)"
на английском языке: получите любой знак пунктуации или специальный символ как caputure группа 1 (\\1)
на английском языке: префикс все специальные символы с обратной косой чертой
на английском языке: если больше чем одно соответствие найдено на той же строке, замените их всех
sed -i -E "s/^(.*)$/#\\1/" ~/.colcmp.arrays.tmp.sh
Выше использования регулярное выражение для добавления префикса каждой строки ~/.colcmp.arrays.tmp.sh с символом комментария удара (#). Я делаю это, потому что позже я намереваюсь выполнить ~/.colcmp.arrays.tmp.sh использование исходной команды и потому что я не знаю наверняка целый формат File_1.txt.
Я не хочу случайно выполнять произвольный код. Я не думаю, что любой делает.
"s / (находят) / (замена) /"
на английском языке: получите каждую строку как caputure группа 1 (\\1)
на английском языке: замените каждую строку символом фунта, сопровождаемым строкой, которая была заменена
sed -i -E "s/^#\\s*(\\S+)\\s+(\\S.*?)\\s*\$/A1\\[\\1\\]=\"\\2\"/" ~/.colcmp.arrays.tmp.sh
Выше ядро этого сценария.
#User1 US
A1[User1]="US"
A2[User1]="US"
(для 2-го файла)"s / (находят) / (замена) /"
на английском языке:
остальная часть получения строки как группа 2 получения
(замена) = A1 \\[\\1 \\] = \"\\2 \"
A1[
запустить присваивание массива в названном массиве A1
]="
]
= близкое присваивание массива, например. A1[
User1]="
США"
=
= оператор присваивания, например, variable=value"
= заключите значение в кавычки для получения пробелов..., хотя теперь, когда я думаю об этом, было бы легче позволить коду выше этого обратные косые черты все к также пробелам обратной косой черты.на английском языке: замените каждую строку в формате #name value
с оператором присваивания массива в формате A1[name]="value"
chmod 755 ~/.colcmp.arrays.tmp.sh
Выше использования chmod для создания исполняемого файла файла сценария массива.
Я не уверен, необходимо ли это.
declare -A A1
Капитал-A указывает, что объявленные переменные будут ассоциативными массивами.
Поэтому сценарий требует удара v4 или больше.
source ~/.colcmp.arrays.tmp.sh
Мы уже имеем:
User value
к строкам A1[User]="value"
, Выше мы получаем сценарий для выполнения его в текущей оболочке. Мы делаем это так, мы можем сохранить значения переменных, которые установлены сценарием. При выполнении сценария непосредственно он порождает новую оболочку, и значения переменных потеряны, когда новая оболочка выходит, или по крайней мере это - мое понимание.
cp "$2" ~/.colcmp.array2.tmp.sh
sed -i -E "s/([^A-Za-z0-9 ])/\\\\\\1/g" ~/.colcmp.array2.tmp.sh
sed -i -E "s/^(.*)$/#\\1/" ~/.colcmp.array2.tmp.sh
sed -i -E "s/^#\\s*(\\S+)\\s+(\\S.*?)\\s*\$/A2\\[\\1\\]=\"\\2\"/" ~/.colcmp.array2.tmp.sh
chmod 755 ~/.colcmp.array2.tmp.sh
declare -A A2
source ~/.colcmp.array2.tmp.sh
Мы делаем то же самое за 1$ и A1, который мы делаем за 2$ и A2. Это действительно должна быть функция. Я думаю в этой точке, этот сценарий путает достаточно, и это работает, таким образом, я не собираюсь фиксировать его.
for i in "${!A1[@]}"; do
# check for users removed
done
Выше циклов через ключи ассоциативного массива
if [ "${A2[$i]+x}" = "" ]; then
Выше подстановки переменных использования для обнаружения различия между значением, которое сброшено по сравнению с переменной, которая была явно установлена на строку нулевой длины.
По-видимому, существует много способов видеть, была ли переменная установлена. Я выбрал тот с большинством голосов.
echo "$i has changed" > Output_File
Выше добавляет пользовательский $i к Output_File
USERSWHODIDNOTCHANGE=
Выше очищает переменную, таким образом, мы можем отслеживать пользователей, которые не изменились.
for i in "${!A2[@]}"; do
# detect users added, changed and not changed
done
Выше циклов через ключи ассоциативного массива
if ! [ "${A1[$i]+x}" != "" ]; then
Выше подстановки переменных использования, чтобы видеть, была ли переменная установлена.
echo "$i was added as '${A2[$i]}'"
Поскольку $i является ключом массива (имя пользователя), $A2 [$i] должен возвратить значение, связанное с текущим пользователем из File_2.txt.
Например, если $i является User1, вышеупомянутыми чтениями как $ {A2 [User1]}
echo "$i has changed" > Output_File
Выше добавляет пользовательский $i к Output_File
elif [ "${A1[$i]}" != "${A2[$i]}" ]; then
Поскольку $i является ключом массива (имя пользователя), $A1 [$i] должен возвратить значение, связанное с текущим пользователем из File_1.txt, и $A2 [$i] должен возвратить значение из File_2.txt.
Выше сравнивает присваиваемые значения за пользовательский $i из обоих файлов..
echo "$i has changed" > Output_File
Выше добавляет пользовательский $i к Output_File
if [ x$USERSWHODIDNOTCHANGE != x ]; then
USERSWHODIDNOTCHANGE=",$USERSWHODIDNOTCHANGE"
fi
USERSWHODIDNOTCHANGE="$i$USERSWHODIDNOTCHANGE"
Выше создает список разделенных запятой значений пользователей, которые не изменились. Примечание там не является никакими пробелами в списке, или иначе следующая проверка должна была бы быть заключена в кавычки.
if [ x$USERSWHODIDNOTCHANGE != x ]; then
echo "no change: $USERSWHODIDNOTCHANGE"
fi
Выше отчетов значение $USERSWHODIDNOTCHANGE, но только если существует значение в $USERSWHODIDNOTCHANGE. Путем это записано, $USERSWHODIDNOTCHANGE не может содержать пробелы. Если этому действительно нужны пробелы, выше мог бы быть переписан следующим образом:
if [ "$USERSWHODIDNOTCHANGE" != "" ]; then
echo "no change: $USERSWHODIDNOTCHANGE"
fi