Вопрос по sed, bash, grep, sorting, awk – Разница между двумя списками с использованием Bash

23

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

 /tmp/oldList
 /tmp/newList

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

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

Тот же вопрос был задан за 4 дня доstackoverflow.com/questions/11099894/… Nahuel Fouilleul

Ваш Ответ

6   ответов
1

Это старый, но для полноты мы должны сказать, что если у вас действительно большой набор, самым быстрым решением будет использование diff для генерации скрипта, а затем его исходный код, например:

#!/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.

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')"
0

Я обычно использую:

diff /tmp/oldList /tmp/newList | grep -v "Common subdirectories"

grep -v опция инвертирует совпадение:

-v, --invert-match Selected lines are those not matching any of the specified pat- terns.

Так что в этом случае он принимаетdiff результаты и опускает те, которые являются общими.

58

Использоватьcomm(1) Команда для сравнения двух файлов. Они оба должны быть отсортированы, что вы можете сделать заранее, если они большие, или вы можете сделать это встроенным в Bashprocess substitution.

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))

и аналогично для новых линий.

5

команда сравнения сделаю сравнение для вас.

например.,

$ diff /tmp/oldList /tmp/newList

См. Выше ссылку на страницу руководства для получения дополнительной информации. Это должно позаботиться о вашей первой части вашей проблемы.

Я просто подчеркну, чтоdiff Команда имеет смешное количество опций для форматирования вывода, что может обеспечить удобный ввод в программу, которая будет обрабатывать различия.
@chepner хорошая точка зрения .. это определенно стоит проверить связанную страницу руководства.
0

Ты пыталсяdiff

$ diff /tmp/oldList /tmp/newList

$ man diff

Похожие вопросы