Bash сравнить имена файлов
Для сравнения двух или нескольких файлов в Linux есть команда diff . Она может сравнивать как отдельные файлы, так и каталоги. Рассмотрим синтаксис, опции команды diff и несколько примеров использования.
Синтаксис команды diff
Команда diff имеет следующий синтаксис:
Мы указываем опции и подаем на вход два или более файлов или директорий, которые нам нужно сравнить.
▍Чтение файлов
- head : чтение начала файла.
- tail : чтение конца файла.
- cat : чтение файла и вывод его содержимого на экран или конкатенация файлов.
▍Итоги
В этом материале мы рассмотрели 21 популярную команду Bash и поговорили о создании псевдонимов для команд. Если вам эта тема интересна — вот цикл публикаций, посвящённый Bash. Здесь можно найти pdf-версию этих публикаций. Кроме того, если вы хотите освоить Bash, помните о том, что тут, как и при изучении любой другой программной системы, важна практика.
Как найти два файла с совпадающими данными в сценарии оболочки и дубликат хранилища данных в другом файле оболочки?
Я написал код, но он не работал. Как это написать?
Чтобы просто проверить, совпадают ли два файла, используйте cmp -s :
Если ваши два входных файла содержит список путей файлов, которые вы хотите сравнить, используйте двойной цикл, например:
Здесь результат создается как на терминале, так и в файле file-comparison.out .
Предполагается, что ни один путь в двух входных файлах не содержит встроенных символов новой строки.
Код сначала считывает все пути из одного из файлов в массив, files1 , с помощью mapfile . Я делаю это, чтобы не читать этот файл более одного раза, так как нам придется просматривать все эти пути для каждого пути в другом файле. Вы заметите, что вместо чтения из $filelist1 во внутреннем цикле я просто перебираю имена в files1 массив.
- мне нужна полная программа в оболочке bash
- @santhoshreddy См. обновленный ответ.
Самый простой способ - использовать команду diff .
пример:
предположим, что первый файл file1.txt и он содержит:
и второй файл file2.txt
тогда мы можем использовать команду diff для автоматического отображения строк, различающихся в двух файлах:
diff file1.txt file2.txt
Давайте посмотрим, что означает этот вывод. Важно помнить, что когда diff описывает вам эти различия, он делает это в предписывающем контексте: он сообщает вам, как изменить первый файл, чтобы он соответствовал второму файлу. Первая строка вывода diff будет содержать:
- номера строк, соответствующие первому файлу,
- буква (a для добавления, c для изменения или d для удаления)
- номера строк, соответствующие второму файлу.
В нашем выводе выше «2,4c2,4» означает: "Строки 2 через 4 в первом файле нужно изменить для соответствия строкам 2 через 4 во втором файле ". Затем он сообщает нам, что эти строки находятся в каждом файле:
- Строки, которым предшествует , являются строками из второго файла.
- Три дефиса («---») просто разделяют строки файла 1 и файла 2.
Вот чистый сценарий оболочки bash для сравнения файлов:
Комментарии к конкретным командам можно удалить, чтобы выйти при первом обнаруженном различии и, если вы хотите, увидеть каждую прочитанную строку.
Подробности о командах
Для начала давайте разберёмся с командами, результаты работы которых выдаются в форме stdout . Обычно эти результаты появляются в окне терминала.
Сравнение двух текстовых файлов
Для простого сравнения двух текстовых файлов с именами myfile1 и myfile2 выполним в терминале команду:
Сравнение директорий, содержащих текстовые файлы
Рассмотрим пример сравнения двух директорий ( mydir1 и mydir2 ), которые содержат текстовые файлы. Основное отличие здесь от примера выше состоит в том, что мы добавим опцию -r , означающую рекурсивный обход файлов в директориях.
Теперь предположим, что в директориях, в которых мы сравниваем файлы, находится много «мусора», который мы не должны сравнивать. Создадим файл excludeFiles и запишем в него шаблоны и названия файлов, которые мы не должны сравнивать. Например, содержимое excludeFiles может иметь вид:
Теперь укажем команде diff, чтобы она использовала наш файл excludeFiles при сравнении каталогов:
Таким образом, мы сравниваем файлы, имена которых не попадают под шаблоны в файле excludeFiles , например, vasya.exe или ChangeLog12 .
Добавим еще несколько опций, которые описаны выше, чтобы улучшить результат сравнения:
Мы сравниваем файлы в директориях mydir1 и mydir2 , игнорируя изменения, связанные с добавлением пустых строк, пробелов, табуляции, а также используем шаблоны имен файлов в excludeFiles , чтобы исключить из сравнения ненужные файлы.
Bash-псевдонимы
Bash-псевдонимы (их ещё называют алиасами или сокращениями) предназначены для создания сокращённых наименований команд или их последовательностей, использование которых вместо обычных команд ускоряет работу. Если у вас, предположим, имеется псевдоним bu , за которым скрывается команда python setup.py sdist bdist_wheel , то для вызова данной команды достаточно воспользоваться этим псевдонимом.
Для создания подобного псевдонима достаточно добавить следующую команду в файл ~/.bash_profile :
Если в вашей системе нет файла ~/.bash_profile , то вы можете создать его самостоятельно, воспользовавшись командой touch . После создания псевдонима перезапустите терминал, после чего вы сможете этим псевдонимом пользоваться. В данном случае ввод двух символов заменяет ввод более чем трёх десятков символов команды, которая предназначена для сборки Python-пакетов.
В ~/.bash_profile можно добавлять псевдонимы для любых часто используемых команд.
▍Поиск
- grep : поиск информации.
- ag : продвинутая команда для поиска.
Опции команды diff
Рассмотрим основные опции команды diff. Я рассмотрю только те опции, которые сам использую наиболее часто.
-E | игнорировать изменения, связанные с добавлением символа табуляции в тексте. |
-b | игнорировать изменения, связанные с добавлением пробелов. |
-w | игнорировать изменения, связанные с добавлением пробелов и табуляции. |
-B | игнорировать новые пустые строки. |
-p (или —show-c-function) | показать название функции языка C, в которой найдены изменения. |
-y (или —side-by-side) | отобразить результаты в две колонки. |
-r | просматривать каталоги рекурсивно. |
-X FILE | исключить из поиска файлы, имена которых совпадают с шаблонами в файле FILE. |
-d (или —minimal) | попытаться найти как можно меньше изменений (то есть исключить ложные срабатывания). |
▍Архивация
▍Перенаправление ввода-вывода и конвейеры
- < : перенаправление stdin .
- > : перенаправление stdout .
- | : перенаправление с помощью конвейера вывода одной команды на вход другой команды.
▍Получение информации
- man : выводит руководство пользователя (справку) по команде.
- pwd : выводит сведения о рабочей директории.
- ls : выводит содержимое директории.
- ps : позволяет просматривать сведения о работающих процессах.
Заключение
Дополнительную информацию по использованию команды diff в вашей системе Linux вы можете получить, выполнив команду:
Также существуют программы, которые позволяют сравнивать файлы, используя графический интерфейс. Например, программа Meld, которая в наглядном виде показывает где и что изменилось в файлах.
У меня есть два файла со списком файлов. Мне нужно проверить, какие файлы отсутствуют в списке второго файла. Проблема в том, что мне не нужно соответствовать полному имени, а нужно только сопоставить последние 19 символов в именах файлов.
MyFile123432 20150510230000.xlsx
MyFile999996 20150510230000.xlsx
Это уникальная проблема, и я не знаю, с чего начать. Пожалуйста, помогите.
▍Поиск
Для поиска данных можно использовать разные команды. В частности — grep , ag и ack . Начнём наше знакомство с этими командами с grep . Это — проверенная временем, надёжная команда, которая, правда, медленнее других и не так, как они, удобна в использовании.
Команда grep
grep my_regex my_file : выполняет поиск my_regex в my_file . При обнаружении совпадений возвращается, для каждого из них, вся строка. По умолчанию my_regex воспринимается как регулярное выражение.
grep -i my_regex my_file : поиск выполняется без учёта регистра символов.
grep -v my_regex my_file : возвращает все строки, в которых не содержится my_regex . Флаг -v означает инверсию, он напоминает оператор NOT , имеющийся во многих языках программирования.
grep -c my_regex my_file : возвращает сведения о количестве совпадений с искомым шаблоном, найденных в файле.
grep -R my_regex my_folder : выполняет рекурсивный поиск во всех файлах, находящихся в заданной папке и в папках, вложенных в неё.
Теперь поговорим о команде ag . Она появилась позже grep , она быстрее, работать с ней удобнее.
ag my_regex my_file : возвращает сведения о номерах строк, и сами строки, в которых найдены совпадения с my_regex .
ag -i my_regex my_file : поиск выполняется без учёта регистра символов.
Команда ag автоматически обрабатывает файл .gitignore и исключает из вывода то, что найдено в папках или файлах, перечисленных в этом файле. Это очень удобно.
ag my_regex my_file -- skip-vcs-ignores : содержимое файлов систем автоматического контроля версий (наподобие .gitignore ) при поиске не учитывается.
Кроме того, для того чтобы указать команде ag на то, какие пути к файлам нужно исключить из поиска, можно создать файл .agignore .
В начале этого раздела мы упомянули о команде ack . Команды ack и ag очень похожи, можно сказать, что они взаимозаменяемы на 99%. Однако команда ag работает быстрее, поэтому я описал именно её.
Теперь поговорим о работе с архивами.
4 ответа
Решение на основе awk:
Или вы можете использовать свои стандартные инструменты coreutil :
Он определит, какие необычные записи отсутствуют в каком файле. Вы также можете манипулировать необычными именами файлов как угодно, например расширение параметра / извлечение подстроки, удаление подстроки или индексы символов.
Итак, если первый файл - это FILE1 , а второй файл - FILE2 , то если цель состоит только в том, чтобы идентифицировать файлы в FILE2 , которых нет в FILE1 , следующее должно сделать:
Вкратце, это меняет местами символы в каждой строке и извлекает интересующую вас часть, сохраняя во временный файл для каждого списка файлов. Переворачивание символов выполняется, поскольку вы не сказали, гарантированно ли длина имен файлов будет постоянной - единственное, на что мы можем здесь положиться, это то, что последние 19 символов имеют фиксированный формат (в данном случае (хотя формат легко определить, на самом деле он не имеет значения). Сортировка важна для того, чтобы diff показал вам, чего нет во втором файле, чем в первом.
Если вы уверены, что когда-либо будут отсутствовать файлы только в FILE2 , а не наоборот (то есть файлы в FILE2 , которых нет в FILE1 ), тогда вы можете очистить вещи, удалив беспорядок, введенный diff , поэтому последняя строка станет:
grep ограничивает вывод теми строками с именами файлов xlsx , а sed удаляет все в строке, начиная с первого встретившегося пробела.
Конечно, технически это только говорит вам, какие сгруппированные по времени группы файлов существуют в FILE1 , но не FILE2 - насколько я понимаю, это то, что вы вы ищете (насколько я понимаю из описания вашей проблемы, MyFile12343220150510230000.xlsx и MyFile99999620150510230000.xlsx будут иметь идентичное содержание). Если имена файлов всегда имеют одинаковую длину (как вы впоследствии подтвердили), тогда нет необходимости в rev , и команды вырезания можно просто изменить, чтобы они ссылались на фиксированные позиции символов.
В любом случае, чтобы получить окончательный список файлов, вам нужно будет использовать «очищенный» вывод для фильтрации содержимого FILE1 ; Итак, изменив приведенный выше сценарий так, чтобы он включал команду "очистки", мы можем отфильтровать нужные файлы с помощью grep - тогда весь сценарий будет выглядеть так:
Расширенная команда grep ( -E ) просто создает регулярное выражение "или" для каждого расширения "отметка времени" и применяет его к первому файлу. Конечно, все это предполагает, что никогда не будет групп временных меток, которые существуют в FILE2 , а не в FILE1 - если это так , то "diff «обработка вывода» должна быть немного умнее.
Сначала вы можете использовать comm , чтобы сопоставить точные имена файлов и получить список файлов, которые не совпадают. Затем вы можете воспользоваться соглашением. Я никогда им не пользовался, но может оказаться полезным.
Или, как последний вариант, вы можете выполнить перебор и для каждой строки в первом файле искать во втором:
Здесь я предположил, что имена файлов заканчиваются 14 цифрами, которые должны совпадать в другом файле, и расширением файла, которое может отличаться от файла к файлу, но оно тоже должно совпадать:
У меня есть два файла, содержащие список файлов. Мне нужно проверить, какие файлы отсутствуют в списке второго файла. Проблема в том, что мне не нужно соответствовать полному имени, но нужно только сопоставить последние 19 символов имен файлов.
MyFile123432 20150510230000.xlsx
MyFile999996 20150510230000.xlsx
это те же файлы.
Это уникальная проблема, и я не знаю, с чего начать. Незлая помощь.
Итак, если первым файлом является FILE1 а второй файл FILE2 то если намерение состоит только в том, чтобы идентифицировать файлы в FILE2 , которых нет в FILE1 , следует сделать следующее:
В двух словах это изменяет символы на каждой строке и извлекает интересующую вас часть, сохраняя во временный файл для каждого списка файлов. Отмена символов выполняется, так как вы не указали, гарантируется ли длина имен файлов constant- --the, единственное, на что мы можем положиться, состоит в том, что последние 19 символов имеют фиксированный формат (в этом случай, хотя формат легко выведен, это не очень актуально). Сорт важен для того, чтобы diff показывал вам, что не во втором файле, который находится в первом.
Если вы уверены, что в FILE2 будут отсутствовать FILE2 а не наоборот (то есть файлы в FILE2 которые не существуют в FILE1 ), тогда вы можете очистить вещи, удалив крут, введенный diff , поэтому последняя строка становится:
grep ограничивает вывод на эти строки именами файлов xlsx , а sed удаляет все по строке из первого найденного пространства.
Конечно, технически это только говорит вам, какие группы файлов с FILE1 времени группами существуют в FILE1 но не FILE2 --as Я понимаю, это то, что вы ищете (мое понимание вашего описания проблемы - это то, что MyFile12343220150510230000.xlsx и MyFile99999620150510230000.xlsx будет иметь идентичный контент). Если имена файлов всегда имеют одинаковую длину (как вы впоследствии подтвердили), тогда нет необходимости, чтобы команды rev и команды cut могли быть изменены, чтобы ссылаться на фиксированные позиции символов.
В любом случае, чтобы получить окончательный список файлов, вам придется использовать "очищенный" вывод для фильтрации содержимого FILE1 ; поэтому, модифицируя вышеприведенный скрипт, чтобы он включал команду "очистка", мы можем отфильтровать файлы, которые вам нужны, используя весь скрипт grep --the, а затем:
Расширенная команда grep ( -E ) просто создает "или" регулярное выражение для каждого timestamp-plus -E xtension и применяет его к первому файлу. Конечно, все это предполагает, что никогда не будет групп timestamp, которые существуют в FILE2 а не в FILE1 --if, в этом случае бит бит "diff output processing" должен быть немного более умным.
Материал, перевод которого мы публикуем сегодня, предназначен для тех, кто хочет освоить командную строку Linux. Умение эффективно пользоваться этим инструментом позволяет экономить немало времени. В частности, речь здесь пойдёт о командной оболочке Bash и о 21 полезной команде. Также мы поговорим о том, как пользоваться флагами команд и псевдонимами Bash, которые позволяют ускорить ввод длинных инструкций.
▍Архивация
tar my_source_directory : объединяет файлы из папки my_source_directory в один файл tarball. Такие файлы удобно использовать для того, чтобы передавать кому-нибудь большие наборы файлов.
Команда tar
Tarball-файлы, создаваемые этой командой, представляют собой файлы с расширением .tar (Tape ARchive). То, что в названии команды и в расширении имён файлов, создаваемых ей, скрыто слово «tape» (лента), говорит о том, как давно существует эта команда.
tar -cf my_file.tar my_source_directory : создаёт tarball-файл с именем my_file.tar с содержимым папки my_source_directory . Флаг -c расшифровывается как «create» (создание), а флаг -f как «file» (файл).
Для извлечения файлов, находящихся в .tar -файле, используется команда tar c флагами -x («extract», извлечение) и -f («file», файл).
tar -xf my_file.tar : извлекает файлы из my_file.tar в текущую рабочую директорию.
Теперь поговорим о том, как сжимать и распаковывать .tar -файлы.
tar -cfz my_file.tar.gz my_source_directory : здесь, с использованием флага -z («zip», алгоритм сжатия) указано, что для сжатия файлов должен использоваться алгоритм gzip (GNU zip). Сжатие файлов позволяет экономить дисковое пространство при хранении таких файлов. Если же файлы планируется, например, передавать другим пользователям, это способствует более быстрой загрузке таких файлов.
Распаковать файл .tar.gz можно, добавив флаг -z к команде извлечения содержимого .tar -файлов, которую мы рассматривали выше. Выглядит это так:
tar -xfz my_file.tar.gz
Надо отметить, что у команды tar есть ещё множество полезных флагов.
▍Манипуляции с файловой системой
cd my_directory : изменение рабочей директории на my_directory . Для того чтобы перейти на один уровень выше в дереве каталогов используйте в качестве my_directory относительный путь ../ .
touch my_file : создание файла my_file по заданному пути.
mkdir my_directory : создание папки my_directory по заданному пути.
mv my_file target_directory : перемещение файла my_file в папку target_directory . При указании целевой директории нужно использовать абсолютный путь к ней (а не конструкцию вроде ../ ).
Команду mv , кроме того, можно использовать для переименования файлов или папок. Например, выглядеть это может так:
mv my_old_file_name.jpg my_new_file_name.jpg
cp my_source_file target_directory : создание копии файла my_source_file и помещение её в папку target_directory .
ln -s my_source_file my_target_file : создание символической ссылки my_target_file на файл my_source_file . Если изменить ссылку, то изменится и исходный файл.
Если файл my_source_file будет удалён, то my_target_file останется. Флаг -s команды ln позволяет создавать ссылки и для директорий.
Теперь поговорим о перенаправлении ввода-вывода и конвейерах.
▍Манипуляции с файловой системой
- cd : изменение рабочей директории.
- touch : создание файла.
- mkdir : создание директории.
- cp : копирование файла.
- mv : перемещение или удаление файла.
- ln : создание ссылки.
Примеры использования команды diff
▍Чтение файлов
head my_file : считывает строки из начала файла и выводит их на экран. Читать можно не только содержимое файлов, но и то, что команды выводят в stdin , используя эту команду в качестве элемента конвейера.
tail my_file : считывает строки из конца файла. Эту команду тоже можно использовать в конвейере.
Head (голова) находится спереди, а tail (хвост) — сзади
Если вы работаете с данными, используя библиотеку pandas, тогда команды head и tail должны быть вам знакомы. Если это не так — взгляните на вышеприведённый рисунок, и вы без труда их запомните.
Рассмотрим другие способы чтения файлов, поговорим о команде cat .
Команда cat либо выводит содержимое файла на экран, либо конкатенирует несколько файлов. Это зависит от того, сколько файлов передано этой команде при вызове.
Команда cat
cat my_one_file.txt : когда этой команде передают один файл — она выводит его в stdout .
Если же передать ей два файла или большее количество файлов, то она ведёт себя по-другому.
cat my_file1.txt my_file2.txt : получив на вход несколько файлов эта команда конкатенирует их содержимое и выведет то, что получилось в stdout .
Если результат конкатенации файлов нужно сохранить в виде нового файла, можно воспользоваться оператором > :
Теперь поговорим о том, как удалять файлы и останавливать процессы.
▍Удаление файлов, остановка процессов
- rm : удаление файла.
- kill : остановка процесса.
▍Получение информации
man command_name : вывод руководства по команде, то есть — справочной информации.
pwd : вывод на экран пути к текущей рабочей директории. В ходе работы с командной строкой пользователю часто нужно узнавать то, где именно в системе он находится.
ls : вывод содержимого директории. Эта команда тоже используется весьма часто.
ls -a : вывод скрытых файлов. Здесь применён флаг -a команды ls . Использование флагов помогает настраивать поведение команд.
ls -l : вывод подробной информации о файлах.
Обратите внимание на то, что флаги можно комбинировать. Например — так: ls -al .
ps : просмотр выполняющихся процессов.
ps -e : вывод сведений обо всех выполняющихся процессах, а не только о тех, которые связаны с текущей оболочкой пользователя. Данную команду часто используют именно в таком виде.
21 Bash-команда
▍Удаление файлов, остановка процессов
rm my_file : удаляет файл my_file .
rm -r my_folder : удаляет папку my_folder и все содержащиеся в ней файлы и папки. Флаг -r указывает на то, что команда будет работать в рекурсивном режиме.
Для того чтобы система не запрашивала подтверждение при выполнении каждой операции удаления файла или папки, воспользуйтесь флагом -f .
kill 012345 : останавливает указанный выполняющийся процесс, давая ему время на корректное завершение работы.
kill -9 012345 : принудительно завершает указанный запущенный процесс. Флаг вида -s SIGKILL означает то же самое, что и флаг -9 .
Термины
В ходе освоения работы в командной строке Linux вам может встретиться множество понятий, в которых полезно будет ориентироваться. Некоторые из них, вроде «Linux» и «Unix», или «командная оболочка» и «терминал», иногда путают. Поговорим об этих и о других важных терминах.
Unix — это популярная операционная система, которая была разработана Bell Labs в 1970-х. Её код был закрытым.
Linux — это самая популярная Unix-подобная операционная система. Она в наши дни используется на множестве устройств, в том числе — и на компьютерах.
Терминал (terminal), или эмулятор терминала — это программа, дающая доступ к операционной системе. Одновременно можно открывать несколько окон терминала.
Оболочка (shell) — это программа, которая позволяет отправлять операционной системе команды, написанные на особом языке.
Bash расшифровывается как Bourne Again SHell. Это — самый распространённый язык командной оболочки, используемый для взаимодействия с операционной системой. Кроме того, оболочка Bash по умолчанию используется в macOS.
Скрипт (script) — это небольшая программа, которая содержит последовательность команд командной оболочки. Скрипты записывают в файлы, использовать их можно многократно. При написании скриптов можно пользоваться переменными, условными конструкциями, циклами, функциями и другими возможностями.
Теперь, когда мы рассмотрели важные термины, хочу отметить, что здесь я буду пользоваться терминами «Bash», «оболочка» и «командная строка» как взаимозаменяемыми, равно как и понятиями «директория» (directory) и «папка» (folder).
Стандартные потоки, которыми мы будем здесь пользоваться — это стандартный ввод (standard input, stdin ), стандартный вывод (standard output, stdout ) и стандартный вывод ошибок (standard error, stderr ).
Если в примерах команд, которые будут приводиться ниже, вы встретите нечто вроде my_whatever — это означает, что данный фрагмент нужно заменить чем-то вашим. Например — именем файла.
Теперь, прежде чем приступать к разбору команд, которым посвящён этот материал, давайте взглянем на их список и на их краткие описания.
▍Перенаправление ввода-вывода и конвейеры
my_command > my_file : перенаправляет результаты работы команды, то есть то, что обычно попадает в stdout и выводится на экран, в файл my_file . Если файл my_file не существует — он создаётся. Если файл существует — он перезаписывается.
Например, после выполнения команды ls > my_folder_contents.txt будет создан текстовый файл, содержащий список того, что находится в текущей рабочей директории.
Если вместо символа > воспользоваться конструкцией >> , то, при условии существования файла, в который перенаправляется вывод команды, этот файл перезаписан не будет. Данные будут добавлены в конец этого файла.
Теперь взглянем на конвейерную обработку данных.
То, что выводит одна команда, подаётся на вход другой команды. Это похоже на подключение одной трубы к другой
В Linux конвейерную обработку данных можно организовать с использованием практически любой правильно составленной команды. Часто говорят, что всё в Linux — это конвейер.
С помощью символа конвейера можно объединять в цепочку несколько команд. Выглядит это так:
Конвейер из нескольких команд можно сравнить с трубопроводом
Обратите внимание на то, что когда команда, находящаяся слева от символа | , выводит что-то в stdout , то, что она вывела, немедленно становится доступным в виде stdin второй команде. То есть оказывается, что, используя конвейер, мы имеем дело с параллельным выполнением команд. Иногда это может привести к неожиданным результатам. Подробности об этом можно почитать здесь.
Теперь поговорим о чтении данных из файлов и о выводе их на экран.
Читайте также: