Как я могу найти строки в одном файле, но не другие, используя скрипты bash?
Представьте файл 1:
#include "first.h"
#include "second.h"
#include "third.h"
// more code here
...
Представьте файл 2:
#include "fifth.h"
#include "second.h"
#include "eigth.h"
// more code here
...
Я хочу получить заголовки, которые включены в файл 2, но не в файл 1, только те строки.
Таким образом, при запуске diff файла 1 и файла 2 будет выдавать:
#include "fifth.h"
#include "eigth.h"
Я знаю, как это сделать в Perl/Python/Ruby, но я хотел бы сделать это без использования другого языка программирования.
Ответы
Ответ 1
Если вам удобно использовать временный файл, попробуйте следующее:
grep include file1.h > /tmp/x && grep -f /tmp/x -v file2.h | grep include
Это
- извлекает все из
file1.h
и записывает их в файл /tmp/x
- использует этот файл для получения всех строк из
file2.h
, которые не содержатся в этом списке
- извлекает все из оставшейся части
file2.h
Он, вероятно, неправильно обрабатывает различия в пробелах и т.д.
EDIT: для предотвращения ложных срабатываний используйте другой шаблон для последнего grep (спасибо jw013 за это):
grep include file1.h > /tmp/x && grep -f /tmp/x -v file2.h | grep "^#include"
Ответ 2
Это однострочный, но не сохраняет порядок:
comm -13 <(grep '#include' file1 | sort) <(grep '#include' file2 | sort)
Если вам нужно сохранить заказ:
awk '
!/#include/ {next}
FILENAME == ARGV[1] {include[$2]=1; next}
!($2 in include)
' file1 file2
Ответ 3
Этот вариант требует fgrep
с опцией -f
. GNU grep (то есть любая система Linux, а затем и некоторые) должны работать нормально.
# Find occurrences of '#include' in file1.h
fgrep '#include' file1.h |
# Remove any identical lines from file2.h
fgrep -vxf - file2.h |
# Result is all lines not present in file1.h. Out of those, extract #includes
fgrep '#include'
Это не требует сортировки или каких-либо явных временных файлов. Теоретически fgrep -f
может использовать временный файл за кулисами, но я считаю, что GNU fgrep
не делает.
Ответ 4
Если цель не должна выполняться только с Bash (т.е. использование внешних программ приемлемо), используйте combine
из moreutils:
combine file1 not file2 > lines_in_file1_not_in_file2
Ответ 5
cat $file1 $file2 | grep '#include' | сортировать | uniq -u