найти совпавшие file_ids в файлах dat в каталоге и скопировать их в другой каталог

310
Jasmine

У меня есть file_id = 840920и я должен выбрать только дочерние файлы, которые принадлежат file_id = 840920. Имена файла данных различны, но во всем файле данных доступен идентификатор родительского файла. Пример записи показан как:

445973129|2602325065|840920|1|RUPATXEM14|LVP|||20180924 18:25:10 445973130|2602325066|840920|2|RP_STG_TEST_WED|LVP|||20180924 18:23 

Поэтому я хочу сопоставить свой поиск только по третьему столбцу, извлечь эти файлы данных и скопировать их в другую папку.

Ниже мой код в Unix, чтобы сделать то же самое. Нужна помощь для большего количества предложений или лучших способов справиться с тем же. Мой запрос заключается в том, что я могу печатать matched_file_idзначения, когда я запускаю цикл while отдельно, но код не печатает, показывая matched_file_idзначения, когда я включил их в свой код: какие-либо предложения, пожалуйста?

cat $TMP/TempBatchData.txt | while read FILE_ID #FILE_ID = 840920 do for file in *CDI*.dat; do echo $file >> all_CDI_LIST.txt done while IFS= read -r line; do matched_file_id=`cat $line | cut -f3 -d"|" | sort -u` # echo all the third  column values done < "all_CDI_LIST.txt"   if [[ $matched_file_id == $FILE_ID ]]; then  echo $line >> final_cdi_list.txt fi done done 
1

1 ответ на вопрос

0
Kamil Maciorowski

Проблемы, подозрительные фрагменты:

  • $matched_file_idсодержит ноль или более значений, сравнение $FILE_IDвыполняется только при наличии одного значения;
  • $matched_file_idустанавливается один раз за line, сравнение $FILE_IDвыполняется один раз за FILE_ID;
  • doneв конце есть дополнительный (?);
  • column values должен принадлежать комментарию;
  • переменные не заключены в кавычки;
  • TMP должен быть установлен.

Это переписанная процедура. Это не совсем эквивалентно, но подход кажется лучше:

TMP="/the/right/path" find . -type f -name '*CDI*.dat' \ -exec sh -c ' <"$1" cut -f3 -d"|" | grep -qFx -f "$TMP/TempBatchData.txt" ' sh {} \; -print > final_cdi_list.txt 

Объяснение:

  1. findнаходит все файлы, соответствующие *CDI*.datшаблону.
  2. Для каждого такого файла запускается оболочка для обработки канала.
  3. cut извлекает третий столбец.
  4. grepquietly ( -q) проверяет, существует ли какая-либо буквальная строка ( -F) из данного файла ( -f) в выходных данных cutкак целая строка ( -x).
  5. Если это так, findбудет напечатан путь к файлу.

Примечания, отличия, причуды:

  • findдействует рекурсивно. Чтобы обработать только текущий каталог без подкаталогов, в которых вы нуждаетесь -maxdepth 1(не требуется POSIX) или POSIX-решение из этого вопроса, или позволить shell расширить *CDI*.dat( find *CDI*.dat -type f -exec …), у которого есть свои недостатки.
  • findбудет печатать пути с ведущими ./. Для получения базовых имен вам нужно -printf '%f\n'(не POSIX) вместо -printили, например, -exec basename {} \;(POSIX-совместимый) вместо -print.
  • grep -Fсоответствует буквенным строкам. В вашем коде каждая строка из $TMP/TempBatchData.txtдважды подвергается неявной обработке:

    1. с read FILE_ID(в отличие от read -r FILE_ID),
    2. внутри [[ $matched_file_id == $FILE_ID ]](сравнение с использованием [[выполнения сопоставления с шаблоном по строке без кавычек с правой стороны, а не просто сравнение по простой строке).


    Я не уверен, если вы полагаетесь на это. Вы можете настроить мой код.

  • В заголовке упоминается копирование файлов в другой каталог. С моим подходом вам не нужно обрабатывать final_cdi_list.txtэто. Просто используйте -exec cp {} "/another/directory" \;вместо -print.

Вся работа по поиску подходящих файлов может быть выполнена с единственным grep, вам нужно настроить шаблон. Пример:

grep -l '^[0-9]*|[0-9]*|840920|' *CDI*.dat 

Вы можете иметь много шаблонов в файле ( -f "$TMP/TempBatchData.txt"), но они должны быть такими же, как указано выше. Если совпадающих файлов слишком много, *CDI*.datвы получите «список аргументов слишком длинный» (подход, который for file in *CDI*.dat;вы использовали изначально, защищен от этого).

Возможно, измените структуру каталогов (например, только *CDI*.datфайлы в текущем каталоге и подкаталогах, рекурсивный поиск разрешен или нет подкаталогов вообще) и формат файла шаблона. Идея состоит в том, чтобы использовать

grep -lr -f "$TMP/TempBatchData.txt" 

или что-то подобное. -rPOSIX не требует примечания, в этом примере его значение от GNU grep: рекурсивно читать все файлы в текущем рабочем каталоге.

Один grepпроцесс должен быть быстрее, чем любое решение, которое использует find -execили read(и сопоставляет строки любым способом).

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