AWK ищет записи в одном файле для записей в другом файле - PullRequest
0 голосов
/ 30 января 2019

У меня есть файл results.csv, который содержит имена в следующем макете:

name1, 2(random number)  
name5, 3

и образец.txt, структурированный в следующем формате

record_seperator
name1
foo
bar
record_seperator
name2
bla
bluh

Я бынапример, искать для каждого имени в results.csv в файле sample.txt и, если оно найдено, вывести запись в файл.Я попытался сгенерировать массив из первого файла и найти его, но не смог получить правильный синтаксис.Это должно работать в скрипте bash.Если у кого-то есть идея получше, чем awk, это тоже хорошо, но у меня нет прав администратора на машине, на которой она должна работать.Настоящий CSV-файл содержит 10.000 имен, а sample.txt - 4.5 миллиона записей.Я - кровавый новичок в awk, поэтому объяснение будет высоко ценится.Это моя текущая попытка, которая не работает, и я не знаю, почему:

#!/bin/bash
awk 'BEGIN{
while (getline < "results.csv")
{
split($0,name,",");
nameArr[k]=name[1];
}
{
RS="record_seperator"
FS="\n"
for (key in nameArr)
        {
         print nameArr[key]
         print $2
         if ($2==nameArr[key])
                 NR > 1
                 {
                #extract file by Record separator and name from line2
                print RS $0 > $2 ".txt"
                }
        }
}
}' sample.txt

edit: мой ожидаемый результат будет два файла:

name1.txt

record_seperator
name1
foo
bar

name2.txt

record_seperator
name2
bla
bluh

Ответы [ 4 ]

0 голосов
/ 30 января 2019

Ошибки вашего кода:

#!/bin/bash
awk 'BEGIN{
while (getline < "results.csv")
{
split($0,name,",");
nameArr[k]=name[1];  ## <-- k not exists, you are rewriting nameArr[""] again and again.
}
{
RS="record_seperator"
FS="\n"
for (key in nameArr) ## <-- only one key "" exists, it's never gonna equal to $2
        {
         print nameArr[key]  
         print $2
         if ($2==nameArr[key])
                 NR > 1
                 {
                #extract file by Record separator and name from line2
                print RS $0 > $2 ".txt"
                }
        }
}
}' sample.txt

Также пример, который вы показали:

name1, 2(random number)  
name5, 3  ## <-- name5 here, not name2 !

Изменено name5 на name2, а ваш собственный код обновлен:

#!/bin/bash
awk 'BEGIN{
    while ( (getline line< "results.csv") > 0 ) {  # Avoid infinite loop when read erorr encountered.
        split(line,name,",");
        nameArr[name[1]]; # Actually no need do anything, just refer once to establish the key (name[1]).
    }
    RS="record_seperator";
    FS="\n";
}

$2 in nameArr {
        print RS $0;  #You can add `> $2 ".txt"` later yourself.
}' sample.txt

Вывод:

record_seperator 
name1            
foo              
bar              

record_seperator 
name2            
bla              
bluh             
0 голосов
/ 30 января 2019

как-то так, ( не проверено )

$ awk -F, 'NR==FNR {a[$1]; next}                  # fill array with names from first file
           $1 in a {print rt, $0 > ($1".txt")}    # print the record from second file
                   {rt = RT}' results.csv RS="define_it_here" sample.txt  

, поскольку ваш разделитель записей находится перед записями, вам нужно отложить его на единицу.

Используйте встроенный итератор строк / записей вместо его обхода.

0 голосов
/ 30 января 2019

(Следуя указаниям @ Tiw, я также изменил name5 на name2 в вашем файле результатов, чтобы получить ожидаемый результат)

$ cat a.awk
# collect the result names into an array
NR == FNR {a[$1]; next}

# skip the first (empty) sample record caused by initial record separator
FNR ==  1 { next }

# If found, output sample record into the appropriate file
$1 in a {
    f =  ($1 ".txt")
    printf "record_seperator\n%s", $0  > f
}

Запуск с gawk для многосимвольного RS:

$ gawk -f a.awk FS="," results.csv FS="\n" RS="record_seperator\n" sample.txt

Результаты проверки:

$ cat name1.txt
record_seperator
name1
foo
bar
$ cat name2.txt
record_seperator
name2
bla
bluh
0 голосов
/ 30 января 2019

Вот один. Поскольку не было ожидаемого вывода, он просто выводит необработанные записи :

$ awk '
NR==FNR {              # process first file 
    a[$1]=RS $0        # hash the whole record with first field (name) as key 
    next               # process next record in the first file
}                      # after this line second file processing
$1 in a {              # if first field value (name) is found in hash a
    f=$1 ".txt"        # generate filename
    print a[$1] > f    # output the whole record
    close(f)           # preserving fds
}' RS="record_seperator\n" sample RS="\n" FS="," results  # file order and related vars

Только одно совпадение:

$ cat name1.txt
record_seperator
name1
foo
bar

Проверено на gawk и mawk, действует странно наоригинал-AWK.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...