1

У меня есть 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

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

  • $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. grep спокойно (-q) проверяет, существует ли какая-либо буквальная строка (-F) из данного файла (-f) в выходных данных cut как целая строка (-x).
  5. Если это так, команда find распечатает путь к файлу.

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

  • find действия рекурсивно. Чтобы обработать только текущий каталог без подкаталогов, вам нужно -maxdepth 1 (не требуется POSIX) или решение POSIX из этого вопроса, или позволить оболочке развернуть *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"

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

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

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .