Сопоставление нескольких файлов с номерами и исключение одного из файлов по номеру - PullRequest
1 голос
/ 05 марта 2019

У меня есть ряд файлов, отсортированных по номеру (File1.txt, File2.txt, File3.txt и т. Д.), В котором я запускаю цикл в моем скрипте как ввод для кода awk. Я могу сопоставить шаблон как

awk ... file[1-$i].txt >> output

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

file$v.txt

цель

Я ищу что-то вроде

awk ... file[1-!$v-$i].txt >> output

где я сопоставляю каждый файл от 1 до $ i, пропуская файл с $ v.


Я пробовал различные входные данные из сопоставления составных шаблонов, как описано здесь , но я не мог заставить синтаксис работать на меня.

Кто-нибудь знает, как подобрать составной шаблон? Спасибо.


Пример ввода

По запросу, вот мои файлы:

file.1.dat

29.078306 0.00676358
29.223592 0.00309192
30.297306 0.0174575
30.478883 0.132458
30.503705 0.118951
30.512891 0.0705088
31.945900 0.00408244
32.321011 0.00258023
32.894037 0.00407912
32.916263 0.00330154
34.594139 0.00874524
34.849178 0.0195172
34.884655 0.00547378
34.967403 0.00308369
35.325397 0.00818193

file.2.dat

25.970535 0.0979715
26.913976 0.00593039
29.078306 0.0984052
29.223592 0.00271504
30.236632 0.013818
30.478883 0.0347606
30.503705 0.102369
30.512891 0.0409633
31.714064 0.0242958
31.902306 0.0510168
32.715764 0.0146584
34.952965 0.00484555
35.190790 0.0114201
35.360372 0.0033089
35.575199 0.00282864
38.184618 0.00551692

file.3.dat

31.591771 0.0126916
32.059389 0.0605918
32.299959 0.122618
32.890418 0.0058495
32.962536 0.00492958
33.646214 0.0705359
33.679538 0.120592

file.4.dat

25.636267 0.00398174
27.848542 0.00485739
28.269278 0.0174401
29.418886 0.00409613
31.313212 0.203932
31.945900 0.00259743
32.256620 0.00325607
32.299959 0.0325366
33.461363 0.0798633
33.646214 0.0516498
33.679538 0.12871

file.5.dat

29.767600 0.00777448
32.299959 0.00777995
34.849178 0.0305844
34.884655 0.0126815
34.930799 0.0546924
34.952965 0.0711241

Код Awk

awk '
NR==FNR {
    a[$1]=$2
    next
}
($1 in a) {
    a[$1]+=$2
}
END {
    for(i in a)
        print i,a[i]
}' file.4.dat file.[1-5].dat >| test.out

Этот код выполняет следующие действия:

  1. Сопоставляет file.4.dat с file.1.dat, file.2.dat ... file.5.dat на основе значения в поле 1 ($ 1).
  2. Где бы ни было найдено совпадение в $ 1, оно добавляет $ 2 к файлу file.4.dat $ 2 в соответствующей строке.
  3. test.out печатает file.4.dat, где $ 2 равно сумме $ 2 из совпадающих строк $ 1.

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

Цель

Моя цель - иметь следующую строку в моем выводе:

33.679538 0.249302

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

33.679538 0.378012

в результате добавления file.4.dat к себе в код awk, поскольку я не могу исключить его во втором аргументе для входного файла.

Краткое изложение проблем

Мой код awk читает все мои входные файлы, и мне нужно исключить 1 из файлов, чтобы получить правильный вывод.

В конечном счете, я должен ввести каждый из моих 5 файлов отдельно против остальных 4 файлов в коде awk выше. В будущем количество файлов будет переменным, поэтому я не могу просто ввести имена файлов в моем скрипте. На данный момент, если я смогу решить эту проблему хотя бы для менее чем 10 файлов, это будет серьезной помощью.

Ответы [ 4 ]

2 голосов
/ 05 марта 2019

Вы можете просто сделать это в awk, указав первый файл, который вы используете для справки, и проигнорировав его для последующей обработки, используя опцию nextfile (требуется версия GNU), которая пропускает обработку файла для последующей обработки. Исходя из этой логики, вы должны разместить справочный файл, например, file.4.dat в качестве входных данных в качестве первого аргумента в списке файлов.

awk '
BEGIN{ ignoreFile = ARGV[1] }
NR==FNR {
    a[$1]=$2
    next
}
FILENAME == ignoreFile { nextfile }
($1 in a) {
    a[$1]+=$2
}
END {
    for(i in a)
        print i,a[i]
}' file.4.dat file.[1-5].dat >| test.out

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

Насколько вы понимаете, у вас есть n файлы, и один из них будет использоваться в качестве справочного файла. Я бы предпочел использовать функцию extglob оболочки bash, чтобы включить все файлы, кроме ссылки. Например, Я создаю файлы file1..10 для объяснения этого

touch file{1..10}
exclude=3

Расширенные параметры оболочки задаются с помощью встроенной shopt 1019 *

shopt -s extglob
list=(!(file"$exclude"))

Теперь напечатайте массив, используя declare -p list, чтобы увидеть список файлов, исключая только эталонный файл. Теперь используйте массив в вашем awk, как показано ниже. Расширение массива "${list[@]}" приводит к исключению всех файлов, созданных вами выше.

awk ... file"$exclude" "${list[@]}"
1 голос
/ 05 марта 2019

Чтобы пропустить файл, вы просто установите ARGV[its position in the arg list] на ноль. e.g.:

$ ls
file1  file2  file3

$ grep . file*
file1:x
file2:y
file3:z

$ awk 'BEGIN{ARGV[2]=""} {print FILENAME, $0}' file*
file1 x
file3 z

или вы можете удалить «плохой» файл по имени, а не по порядку в списке аргументов, если вы предпочитаете:

$ awk 'BEGIN{for (i in ARGV) if (ARGV[i]=="file2") ARGV[i]=""} {print FILENAME, $0}' file*
file1 x
file3 z

$ awk 'BEGIN{bad["file2"]; for (i in ARGV) if (ARGV[i] in bad) ARGV[i]=""} {print FILENAME, $0}' file*
file1 x
file3 z

$ awk '
    BEGIN {
        split("file2 file3",tmp); for (i in tmp) bad[tmp[i]]
        for (i in ARGV) if (ARGV[i] in bad) ARGV[i]=""
    }
    {print FILENAME, $0}
' file*
file1 x
0 голосов
/ 05 марта 2019

Использование конвейерных awks.Вы должны предоставить последний файл в качестве ссылки (здесь-> 4)

awk ' $(NF+1)=FILENAME' file.[1-3].dat file.5.dat file.4.dat |  
   awk ' { a[$1]+=$2; $2=a[$1] } /file.4.dat/ && NF-- '

с указанными файлами

$ awk ' $(NF+1)=FILENAME' file.[1-3].dat file.5.dat file.4.dat |  
      awk ' { a[$1]+=$2; $2=a[$1] } /file.4.dat/ && NF-- '
25.636267 0.00398174
27.848542 0.00485739
28.269278 0.0174401
29.418886 0.00409613
31.313212 0.203932
31.945900 0.00667987
32.256620 0.00325607
32.299959 0.162935
33.461363 0.0798633
33.646214 0.122186
33.679538 0.249302

$
0 голосов
/ 05 марта 2019

Если кто-то не хочет использовать ИЛИ не имеет nextfile в своей системе, может помочь следующее.

awk -v ignore="file.4.dat" '
FNR==1{
    no_parse=""
}
FNR==NR {
    a[$1]=$2
    next
}
FILENAME == ignore{
    no_parse=1
}
no_parse{
    next
}
($1 in a) {
    a[$1]+=$2
}
END {
    for(i in a)
        print i,a[i]
}' file.4.dat file.[1-5].dat >| test.out

Создала переменную с именем ignore, и мы могли бы упомянуть файл Input_file, который нам нужно игнорировать там, как только этот разбор Input_file наступит для разбора, я установил флаг с именем no_parse в TRUE, в этом случае конкретное содержимое Input_file не будет быть прочитанным (поскольку next используется для пропуска всех дальнейших операторов)

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