Извлечение столбцов из огромного текстового файла с разделителями.

Я могу дать лишь несколько общий ответ, но, надеюсь, он укажет вам правильное направление.

Вы не сказали, какую x86-плату вы используете, но в недревних системах шина ISA будет находиться за мостом PCI-to-ISA. Вы можете использовать lspci, чтобы найти этот мост. Мост обеспечивает сопоставление основной памяти и пространства ввода-вывода с памятью шины ISA и пространством ввода-вывода. Это устанавливается ядром при загрузке в соответствии с информацией, указанной в BIOS, а именно ACPI, включая устаревший PNP. Вы можете увидеть информацию об этом процессе в dmesg после загрузки.

Даже в современной системе все еще есть устаревшие устройства ISA, хотя теперь они подключены к шине LPC, а не к реальной шине ISA.Драйверы ядра Linux для такого устройства, т. е. драйвер клавиатуры/мыши 8042 PS/2 (см. drivers/input/serio), затем резервируют необходимые им порты (request_region) при инициализации ( i8042_platform_init в i8042-io.h), освободить их при выходе и перенаправить ввод-вывод (inb, outb и т. д. ) общаться с ним. Я не знаю, как это работает для доступа к памяти, но, вероятно, похоже. Зарезервированные порты отображаются в /proc/ioports.

Мост должен отображаться в /sys/bus/pci/devices, возможно, там вы найдете дополнительную информацию. Также есть /sys/bus/isa, но я не уверен, при каких обстоятельствах ядро ​​будет заполнять его информацией.

Итак, сначала я бы попробовал проверить, реагирует ли плата на некоторые порты ввода/вывода. Также попробуйте процедуру перечисления PNP (или проверьте dmesg, если это еще не сделано при загрузке), если она отвечает на это, остальное будет намного проще.

Наконец, я бы попытался выяснить, как ваш мост PCI-to-ISA отображает пространство памяти, какие операции ядра вам нужны, чтобы зарезервировать это пространство памяти, а затем вы можете снова проверить его и посмотреть, не произойдет ли что-нибудь.

Правка:

В книге Linux Device Drivers, 3rd edition есть некоторая информация о доступе к памяти ISA в разделе 9.4.5.

Изменить:

Что попробовать:

1) Загрузитесь с lilo вместо grub, включите "дыру" (ISA-mapping) в BIOS , посмотрите, загружается ли он. Да, lilo все еще работает.

2) Погуглите VIA VT82C686A South Bridge техпаспорт. В пространстве конфигурации PCI, если мост PCI-to-ISA, есть следующий регистр:

Offset 43 - ROM Decode Control  

Setting these bits enables the indicated address range to be
included in the ROMCS# decode:  

7    FFFE0000h-FFFEFFFFh  
6    FFF80000h-FFFDFFFFh 
5    000E8000h-000EFFFFh  
4    000E0000h-000E7FFFh 
3    000D8000h-000DFFFFh  
2    000D0000h-000D7FFFh  
1    000C8000h-000CFFFFh 
0    000C0000h-000C7FFFh  

Так что, я думаю, вы можете попробовать включить «дыру» (отображение ISA) после загрузки и проверить с помощью логического анализатора, работает ли он. Также стоит попробовать использовать FFFE0000h вместо 000E0000h, если карта не декодирует старшие биты.

Я не знаю, как правильно это сделать и сообщить ядру Linux об изменении отображения. Может быть, есть также варианты загрузки для этого.

Я знаю, что вы можете получить доступ к конфигурационному пространству PCI через псевдофайл /sys/bus/pci/devices/0000:00:07.0/config, так что вы даже можете попробовать это вне ядра Водитель.

3) Обязательно проверьте dmesg и /sys/bus/pnp, чтобы убедиться, что ваша карта уже выполняет перечисление. Если вы не можете понять вывод dmesg, поместите его в pastebin и опубликуйте ссылку; Я могу посмотреть.

0
09.03.2017, 18:41
4 ответа

Попробуйте использовать grep.

(
  export LC_ALL=C
  grep -E '^(BL|FR|[GMTW]F|GP|M[CQ]|NC|PM|RE|YT)([^|]*\|){19}TRUE(\||$)' |
    cut -d'|' -f1-3,6,10,11,13,19,20
)

Как предложил @don_crissti, и предполагая, что все строки содержат не менее 20 полей, вы также можете попробовать сначала вырезать, что в зависимости от количества и длины полей в каждой строке и доли совпадающих строк может дать лучшую производительность:

(
  export LC_ALL=C
  cut -d'|' -f1-3,6,10,11,13,19,20 |
    grep -xE '(BL|FR|[GMTW]F|GP|M[CQ]|NC|PM|RE|YT).*\|TRUE'
)
3
28.01.2020, 02:16

Использование подхода python per line-

Приведенный ниже сценарий возвращает произвольный набор столбцов в вашей строке, если первый столбец равен определенной строке. И требуемое соответствие, и возвращаемые столбцы являются аргументами для запуска скрипта. Пример:

python3 /path/to/script.py /path/to/file.txt monkey 3 12 > output.txt

возвращает столбцы 0, 2 и 11 (первый столбец - 0) строки в файле file.txt, если первый столбец равен "monkey"

Время выполнения

На файле размером 30.000.000 строк и объемом несколько гигабайт скрипт выполнил работу менее чем за минуту на моем более чем 10-летнем компьютере. Поскольку скрипт читает и обрабатывает по строке, мы можем предположить, что потребляемое время более или менее линейно, и скрипт выполнит работу значительно быстрее, чем ваша команда.

Скрипт

#!/usr/bin/env python3
import sys

s = sys.argv[2]; cols = [int(n) for n in sys.argv[3:]]

with open(sys.argv[1]) as src:
    for l in src:
        l = l.split("|"); match = l[0].strip()
        if match == s:
            print(match, " ".join(list(l[i].strip() for i in cols)))

Как использовать

  1. Скопируйте скрипт в пустой файл, сохраните его как get_cols.py
  2. Запустите его со следующими аргументами:

    • исходный файл
    • требуемое совпадение первого столбца (строка)
    • столбцы для вывода

    Например:

    python3 /path/to/get_cols.py Germany 2 12 > output.txt
    

Вот и все

0
28.01.2020, 02:16

Вы могли бы хотя бы избавиться от сокращения :

awk -F '|' 'BEGIN { OFS=FS } $20 == "TRUE" && /^(BL|FR|GF|GP|MC|MF|MQ|NC|PF|PM|RE|TF|WF|YT)/ { print $1,$2,$3,$6,$10,$11,$13,$19,$20 }' indata >outdata

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

Вы также можете попробовать сначала вырезать правильные столбцы (чтобы сократить работу awk до простой фильтрации):

cut -d '|' -f 'columnspec' indata | awk -F '|' 'BEGIN { OFS=FS } $20 == "TRUE" && /^(BL|FR|GF|GP|MC|MF|MQ|NC|PF|PM|RE|TF|WF|YT)/ { print }' >outdata

Другой подход - разделить файл на управляемые части, фильтровать их параллельно , а затем объедините результат. См. Руководство для split в вашей системе Unix. Возможно, вам придется использовать флаг -a с разделением, если вы генерируете много сотен файлов, но я бы рекомендовал подсчитать количество строк в файле данных и разделить примерно на 10 файлов. .

1
28.01.2020, 02:16

Попробовать мок? Используйте версию 1.34 или выше. Возможное ускорение задачи, обрабатывающей большой файл, может быть 8-кратным в примере некоторых людей:

big-data-munging-language/

Чтобы провести абсолютное сравнение с вашей текущей производительностью, эта задача заняла 1 минуту (с mawk) для обработки 1 ГБ. Попытка использовать код Java (JIT) была не быстрее.

Кроме того, производительность многих утилит снизилась после добавления поддержки UTF-8. поиск в Google предполагает, что это может очень сильно повлиять по крайней мере на некоторые версии awk: попробуйте запустить с переменной окружения LC_ALL=C (например, LC_ALL=C awk... ).

1
28.01.2020, 02:16

Теги

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