Подтвердить что ты не робот

Разница между двумя списками с использованием Bash

Хорошо, у меня есть два связанных списка на моем поле linux в текстовых файлах:

 /tmp/oldList
 /tmp/newList

Мне нужно сравнить эти списки, чтобы увидеть, какие строки были добавлены и какие строки были удалены. Затем мне нужно перебрать эти строки и выполнить над ними действия в зависимости от того, были они добавлены или удалены.

Как мне сделать это в Bash?

4b9b3361

Ответ 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 и опускает те, которые являются общими.