Выходная часть каждой строки в отдельный файл

Я не уверен, что понимаю вопрос правильно, но если Вы хотите найти дублирующегося дюйм/с в файле как тот выше, просто поместить один IP, на строку затем прокручивает его sort и затем uniq -c который сообщит о количестве идентичных строк перед каждым:

cat config_IP.txt | sed "s/\s\s*/\n/g" | sort | uniq -c

Если Вы хотите проверить другого дюйм/с по файлу, можно просто сгруппировать его с cat:

( cat config_IP.txt; echo "12.34.56.78 90.101.121.131" ) \
    | sed "s/\s\s*/\n/g" | sort | uniq -c

Вы могли бы также хотеть добавить некоторых grep отфильтровывать строки, не содержащие IP-адреса, прежде чем Вы начнете сортировать.

14
13.11.2014, 21:29
4 ответа

Вот один из способов вы можете сделать это с GNU SED:

<infile sed -r 's:(\w+)\s+(\w+):echo \2 > \1.seq:e; d'

или более эффективно, как предложено Гленн Джекман :

<infile sed -r 's:(\w+)\s+(\w+):echo \2 > \1.seq:' | sh
3
27.01.2020, 19:50

с использованием AWK :

awk '{printf "%s\n", $2>$1".seq"}' file

из назначенного файла , распечатайте второе поле в каждой записи ( $ 2 ) к файлу, названному после первого поля ( $ 1 ) с .sq , добавлено к названию.

Как Thor указывает в комментариях в комментариях, для большого набора данных вы можете исчерпать файловые дескрипторы, поэтому он будет разумным закрыть каждый файл после написания :

awk '{printf "%s\n", $2>$1".seq"; close($1".seq")}' file
12
27.01.2020, 19:50

Реализация чистой оболочки:

while read -r filename content ; do
    printf '%s\n' "$content" >> "${filename}.seq"
done < /source/file
13
27.01.2020, 19:50

Мой ответ был бы awk , но если вы обрабатываете много строк - а я говорю о миллионах - вы, скорее всего, увидите реальную выгоду от перехода на "настоящий" язык программирования.

Имея это в виду (и awk уже воспринимается как ответ), я написал несколько реализаций на разных языках и проверил их на одном и том же 10,0000-строчном наборе данных на PCI-E SSD.

me* (C)                0m1.734s
me (C++)               0m1.991s
me (Python/Pypy)       0m2.390s
me (perl)              0m3.024s
Thor+Glenn (sed|sh)    0m3.353s
me (python)            0m3.359s
jasonwryan+Thor (awk)  0m3.779s
rush (while read)      0m6.011s
Thor (sed)             1m30.947s
me (parallel)          4m9.429s

С первого взгляда C выглядит лучше всего, но это свинья, которая так быстро бегает. Pypy и C++ гораздо проще писать и выполнять достаточно хорошо , если только речь не идет о многих миллиардах строк. Если бы это было так, то обновление для выполнения всего этого в оперативной памяти или на SSD может быть лучшим вложением, чем улучшение кода.

Очевидно, что за то время, которое я потратил на это, вы могли бы обработать несколько сотен миллионов записей в самом медленном варианте . Если вы можете писать только awk или Bash циклы, то сделайте это и продолжайте жить дальше. Очевидно, что сегодня у меня было слишком много свободного времени.

Я также протестировал некоторые многопоточные опции (на C++ и Python, а также гибриды с GNU parallel), но накладные расходы потоков полностью перевешивают любую выгоду от такой простой операции (разбиение строк, запись).

Perl

awk (gawk здесь) был бы, честно говоря, моим первым портом вызова для тестирования подобных данных, но вы можете делать довольно похожие вещи на Perl. Похожий синтаксис, но с немного лучшей обработкой записи.

perl -ane 'open(my $fh, ">", $F[0].".seq"); print $fh $F[1]; close $fh;' infile

Python

I like Python. Это мой рабочий язык, и это просто красивый, солидный и невероятно читабельный язык. Даже новичок может догадаться, что здесь происходит.

with open("infile", "r") as f:
    for line in f:
        id, chunk = line.split()
        with open(id + ".seq", "w") as fw:
            fw.write(chunk)

Вы должны помнить, что ваш дистрибутив python двоичный не единственная реализация Python. Когда я прогонял этот же тест через Pypy, он был быстрее, чем C без дальнейшей логической оптимизации. Имейте это в виду, прежде чем списать Python как "медленный язык".

C

Я начал этот пример, чтобы посмотреть, что мы на самом деле можем заставить мой процессор делать, но, честно говоря, C - это кошмар для кодирования, если вы не прикасались к нему долгое время. В этом есть и обратная сторона: он ограничен 100-часовыми строками, хотя расширить его очень просто, просто он мне не понадобился.

Моя оригинальная версия была медленнее, чем C++ и pypy, но после блога об этом я получил некоторую помощь от Джулиана Клода . Эта версия в настоящее время является самой быстрой из-за его подкорректированные буферы ввода-вывода. Это также лот длиннее и вовлеченнее всего.

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>

#define BUFLEN (8 * 1024)

int main(void) {
    FILE *fp;
    FILE *fpout;

    char line[100];
    char *id;
    char *token;
    char *buf = malloc(BUFLEN);

    fp = fopen("infile", "r");

    setvbuf ( fp , buf , _IOLBF, BUFLEN );
    while (fgets(line, 100, fp) != NULL) {
        id = strtok(line, "\t");
        token = strtok(NULL, "\t");

        char *fnout = malloc(strlen(id)+5);
        fnout = strcat(fnout, id);
        fnout = strcat(fnout, ".seq");

        fpout = fopen(fnout, "w");
        setvbuf ( fpout , NULL , _IONBF , 0 );
        fprintf(fpout, "%s", token);
        fclose(fpout);
    }
    fclose(fp);

    return 0;
}

C++

Выполняется хорошо и это намного проще в написании, чем реальный C. У вас есть всевозможные вещи, которые держат вас за руку (особенно, когда дело касается строк и ввода). Всё это означает, что вы можете на самом деле упростить логику. strtok в C - это хог, потому что он обрабатывает всю строку, а затем нам нужно сделать все это утомительное выделение памяти. Она просто проходит вдоль строки, пока не перейдет в закладку, и мы вытаскиваем сегменты, когда они нам нужны.

#include <fstream>
#include <string>
using namespace std;

int main(void) {
    ifstream in("infile");
    ofstream out;
    string line;

    while(getline(in, line)) {
        string::size_type tab = line.find('\t', 0);
        string filename = line.substr(0, tab) + ".seq";
        out.open(filename.c_str());
        out << line.substr(tab + 1);
        out.close();
    }

    in.close();
}

GNU Parallel

(Не версия Moreutils). Это хороший лаконичный синтаксис, но OMGSLOW. Возможно, я использую его неправильно.

parallel --colsep '\t' echo {2} \> {1}.seq <infile

Генератор тестового жгута

Вот мой генератор данных для 100000 строк [ATGC]*64. Он не быстрый и улучшения очень приветствуются.

cat /dev/urandom | tr -dc 'ATGC' | fold -w 64 | awk 'NR>100000{exit}{printf NR"\t"$0"\n"}' > infile
16
27.01.2020, 19:50

Теги

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