Разница между двумя списками с использованием Bash
Хорошо, у меня есть два связанных списка на моем поле linux в текстовых файлах:
/tmp/oldList
/tmp/newList
Мне нужно сравнить эти списки, чтобы увидеть, какие строки были добавлены и какие строки были удалены. Затем мне нужно перебрать эти строки и выполнить над ними действия в зависимости от того, были они добавлены или удалены.
Как мне сделать это в Bash?
Ответы
Ответ 1
Используйте команду comm(1)
для сравнения двух файлов. Они должны быть отсортированы, что вы можете сделать заранее, если они большие, или вы можете сделать это с помощью bash замены процесса.
comm
может принимать комбинацию флагов -1
, -2
и -3
, указывающих, какой файл должен подавлять строки (уникальные для файла 1, уникальные для файла 2 или общие для обоих).
Чтобы получить строки только в старом файле:
comm -23 <(sort /tmp/oldList) <(sort /tmp/newList)
Чтобы получить строки только в новом файле:
comm -13 <(sort /tmp/oldList) <(sort /tmp/newList)
Вы можете передать это в цикл while read
для обработки каждой строки:
while read old ; do
...do stuff with $old
done < <(comm -23 <(sort /tmp/oldList) <(sort /tmp/newList))
и аналогично для новых строк.
Ответ 2
Команда diff сделает сравнение за вас.
например,
$ diff /tmp/oldList /tmp/newList
Смотрите выше ссылку на страницу руководства для получения дополнительной информации. Это должно позаботиться о вашей первой части вашей проблемы.
Ответ 3
Рассмотрите возможность использования Ruby, если ваши скрипты нуждаются в удобочитаемости.
Чтобы получить строки только в старом файле:
ruby -e "puts File.readlines('/tmp/oldList') - File.readlines('/tmp/newList')"
Чтобы получить строки только в новом файле:
ruby -e "puts File.readlines('/tmp/newList') - File.readlines('/tmp/oldList')"
Вы можете передать это в цикл чтения while для обработки каждой строки:
while read old ; do
...do stuff with $old
done < ruby -e "puts File.readlines('/tmp/oldList') - File.readlines('/tmp/newList')"
Ответ 4
Это старо, но для полноты мы должны сказать, что если у вас действительно большой набор, самым быстрым решением будет использование diff для создания script, а затем его источник:
#!/bin/bash
line_added() {
# code to be run for all lines added
# $* is the line
}
line_removed() {
# code to be run for all lines removed
# $* is the line
}
line_same() {
# code to be run for all lines at are the same
# $* is the line
}
cat /tmp/oldList | sort >/tmp/oldList.sorted
cat /tmp/newList | sort >/tmp/newList.sorted
diff >/tmp/diff_script.sh \
--new-line-format="line_added %L" \
--old-line-format="line_removed %L" \
--unchanged-line-format="line_same %L" \
/tmp/oldList.sorted /tmp/newList.sorted
source /tmp/diff_script.sh
Линии, измененные, будут отображаться как удаленные и добавленные. Если вам это не нравится, вы можете использовать -changed-group-format. Проверьте справочную страницу diff.
Ответ 5
Вы пробовали diff
$ diff /tmp/oldList /tmp/newList
$ man diff
Ответ 6
Я обычно использую:
diff /tmp/oldList /tmp/newList | grep -v "Common subdirectories"
Опция grep -v
инвертирует совпадение:
-v, --invert-match Выбранные строки - это строки, которые не соответствуют ни одной из указанных крачек pat-.
Так что в этом случае он принимает результаты diff
и опускает те, которые являются общими.