Можно ли извлечь определенные строки из файла, где первый столбец содержит идентификатор, соответствующий именам других файлов?

#file #awk #sed #file-io #io

Вопрос:

Вчера я задал этот вопрос как часть более широкого вопроса. Комментатор предложил разделить его на свой собственный вопрос.

У меня есть x-файлы. Содержимое первых пяти файлов показано ниже. На второй строке i находится счетчик, так что i = 0 для первого файла. Рядом с i is time , и он всегда увеличивается на 0,5, когда i увеличивается на 1.

Однако я сохранил только каждый x-й файл. Итак, пока i = 0 для первого файла, который у меня есть, i = 100 во втором файле и так далее.

 6 # This file is called "0.xyz" (lt;--the "6" is the same in all files) i = 0, time = 0.000, k = 9000000000000 X -7.6415350292 6.0494971539 8.1919697993 Y -6.6418362233 5.9231018862 8.4056822626 Y -8.0518670684 6.3158684817 9.0061271154 X 26.8252967820 20.4661074967 17.8025744066 Y 26.4477411207 20.4071029058 16.9121571912 Y 26.4399648474 21.2950722068 18.1009273227  6 # This file is called "100.xyz" i = 100, time = 50.000, k = 2500000000000 X -6.2423192714 -1.5704681396 -9.5648670474 Y -5.4925100813 -1.6522059045 -8.9030589772 Y -6.7765278574 -2.3616512405 -9.4776648590 X 4.1248924594 27.8487302083 -17.5400886312 Y 4.1238657681 26.9869907778 -17.9727402579 Y 5.0750649402 28.1292768156 -17.6848507559  6 # This file is called "200.xyz" i = 200, time = 100.000, k = 3945000000000 X 19.0090162215 -5.9338939011 6.1931167954 Y 18.4748060757 -6.4905073540 5.6656446036 Y 19.2825591449 -6.4479943255 7.0179774953 X 11.0203415273 34.6029396705 2.7220660957 Y 11.1184002007 34.8398120338 1.8089008500 Y 10.3349649622 33.9509485292 2.5605794622  6 # This file is called "300.xyz" i = 300, time = 150.000, k = 2341000000000 X -7.6415350292 6.0494971539 8.1919697993 Y -6.6418362233 5.9231018862 8.4056822626 Y -8.0518670684 6.3158684817 9.0061271154 X 26.8252967820 20.4661074967 17.8025744066 Y 26.4477411207 20.4071029058 16.9121571912 Y 26.4399648474 21.2950722068 18.1009273227  6 # This file is called "400.xyz" i = 400, time = 200.000, k = 2500000000000 X -6.2423192714 -1.5704681396 -9.5648670474 Y -5.4925100813 -1.6522059045 -8.9030589772 Y -6.7765278574 -2.3616512405 -9.4776648590 X 4.1248924594 27.8487302083 -17.5400886312 Y 4.1238657681 26.9869907778 -17.9727402579 Y 5.0750649402 28.1292768156 -17.6848507559  

Что я хотел бы сделать, так это сопоставить эти файлы (выше) с данными из другого файла (ниже). В файле ниже каждая строка соответствует одному файлу выше в соответствии с i (Шагом). Затем я хотел бы распечатать первые три столбца соответствующих строк в файле ниже в новый файл.

Хотя я включил имена файлов, я бы предпочел сопоставлять их с помощью i , а не с именами файлов.

Я знаю, как это сделать с помощью простой итерации. Что означает, что я могу посчитать и распечатать каждую x-ю строку файла ниже в новый файл. Тем не менее, я хотел бы использовать более сложный подход, который конкретно соответствует i , потому что это очень длинные файлы, и потенциально могут отсутствовать строки, так что в итоге я получу несоответствие между файлами выше и тем, который я хочу здесь.

 # Step Time Ax Ay Az Bx By Bz Cx Cy Cz Final   0 0.000 14.8032123290 0.0000000000 0.0000000000 0.0000000000 14.8032123290 0.0000000000 0.0000000000 0.0000000000 14.8032123290 3243.9033438318  1 0.500 14.8029498502 0.0000000000 0.0000000000 0.0000000000 14.8029498502 0.0000000000 0.0000000000 0.0000000000 14.8029498502 3243.7307919244  2 1.000 14.8026923814 0.0000000000 0.0000000000 0.0000000000 14.8026923814 0.0000000000 0.0000000000 0.0000000000 14.8026923814 3243.5615395313  3 1.500 14.8024398604 0.0000000000 0.0000000000 0.0000000000 14.8024398604 0.0000000000 0.0000000000 0.0000000000 14.8024398604 3243.3955453870  4 2.000 14.8021922354 0.0000000000 0.0000000000 0.0000000000 14.8021922354 0.0000000000 0.0000000000 0.0000000000 14.8021922354 3243.2327751298 ...  100 50.000 14.8032123290 0.0000000000 0.0000000000 0.0000000000 14.8032123290 0.0000000000 0.0000000000 0.0000000000 14.8032123290 3243.9033438318 ...  200 100.000 14.8029498502 0.0000000000 0.0000000000 0.0000000000 14.8029498502 0.0000000000 0.0000000000 0.0000000000 14.8029498502 3243.7307919244 ...  300 150.000 14.8026923814 0.0000000000 0.0000000000 0.0000000000 14.8026923814 0.0000000000 0.0000000000 0.0000000000 14.8026923814 3243.5615395313  301 150.500 14.8024398604 0.0000000000 0.0000000000 0.0000000000 14.8024398604 0.0000000000 0.0000000000 0.0000000000 14.8024398604 3243.3955453870 ...  400 200.000 14.8021922354 0.0000000000 0.0000000000 0.0000000000 14.8021922354 0.0000000000 0.0000000000 0.0000000000 14.8021922354 3243.2327751298  

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

 0 0.000 14.8032123290   100 50.000 14.8032123290  200 100.000 14.8029498502  300 150.000 14.8026923814  400 200.000 14.8021922354  

Если у кого-нибудь есть какие-либо намеки на то, как подойти к этому, я был бы признателен.

Комментарии:

1. Пожалуйста, добавьте к своему вопросу (без комментариев): Что вы искали и что вы нашли? Что вы пробовали и как это получилось?

2. каждый вопрос должен стоять сам по себе; это означает, что ввод(ы) образцов должен соответствовать (ожидаемым) выводам (выводам) … здесь это не так; Я бы предложил обновить вопрос, чтобы показать соответствующие данные (между входами и выходами); в качестве альтернативы, поскольку мы знаем, что первые 6 файлов были извлечены из одного файла большего размера (см. Ссылку на предыдущие вопросы и ответы), может быть, имеет смысл (вместо этого) предоставить образец файла большего размера и соответствующий (ожидаемый) вывод; как только вы найдете приемлемый ответ, вы сможете объединить эти два вопроса и ответа в один сценарий (для удовлетворения вашего первоначального требования из 2 частей)

3. @markp-фусо, спасибо. Я понимаю, что вы имеете в виду, и надеюсь, что теперь вопрос прояснился.

4. в какой-то момент вы указываете совпадения … в соответствии с i (шагом) и временем , а затем вы указываете соответствие, используя i или время ; не могли бы вы обновить вопрос, чтобы уточнить требования к соответствию … i *AND* time или i *OR* time ?

5. @markp-фусо, да, я был бы рад, если бы смог найти место, которое вызывает путаницу. Я параноик, поэтому предпочел бы сопоставить » я » И «время», но было бы неплохо сопоставить только «я».

Ответ №1:

Вы можете использовать awk скрипт для этого следующим образом:

 awk 'FNR == 1 { if ($0 ~ /^i =/) {  dataFile = 0;  step[$3 0] = FILENAME; } else {dataFile = 1;} }  dataFile == 1 amp;amp; step[$1] {  print $1, $2, $3; }' *.xyz data.txt  

(предполагается, что вызывается конечный файл data.txt ; при необходимости измените)

FNR == 1 соответствует первой строке каждого файла и либо захватит шаг из xyz файла, либо установит флаг, указывающий, что мы достигли файла данных. $3 0 Бит просто заставит awk преобразовать 3-е поле в число (т. Е. Удалить конечную запятую) из-за запроса на выполнение математической операции.

dataFile == 1 amp;amp; step[$i] соответствует строкам в файле данных, в которых значение шага было замечено в xyz файле.

ПРИМЕЧАНИЕ: Вы должны указать все xyz файлы перед окончательным файлом данных, чтобы все шаги были собраны до обработки файла данных.


Извините, когда я собрал вышеприведенное решение вместе, я думал # This file is called , что строки не являются частью файла. Измененный сценарий находится здесь:

 awk ' FNR == 2 amp;amp; FILENAME != ARGV[ARGC-1] {  step[$3 0] = FILENAME; }  FILENAME == ARGV[ARGC-1] amp;amp; step[$1] {  print $1, $2, $3; }' *.xyz data.txt   

Эта версия использует ARGV и ARGC для определения того, обрабатывается ли файл «данные».

  • Если нет файла данных и номера строки == 2, кэшируйте значение «шаг».
  • Если файл данных и шаг указаны в списке, распечатайте первые 3 поля

Результат:

 0 0.000 14.8032123290 100 50.000 14.8032123290 200 100.000 14.8029498502 300 150.000 14.8026923814 400 200.000 14.8021922354  

Комментарии:

1. большое спасибо. Awk намного быстрее Python (к которому я привык) для работы с огромными файлами, но у меня недостаточно опыта, чтобы делать то, что мне иногда нужно. Спасибо, что просветили меня!

2. @markp-fuso, вы удалили первую строку файлов .xyz (ту, в которой стоит «6»)?

3. @markp-фусо, прошу прощения, я должен был сказать, как и вы, что сценарий можно изменить, чтобы получить доступ к правильной строке. Удаление строки имеет еще одно преимущество для моей конкретной ситуации. Спасибо вам обоим за всю вашу помощь. Мои файлы имеют длину в сотни тысяч строк, и использование метода Awk для работы с ними намного быстрее и надежнее, чем то, что я делал.

4. @markp-фусо: Да, я забыл включить строку «6» в файлы. Я обновил ответ и оставил исходный сценарий для справки.

Ответ №2:

Допущения:

  • совпадения основаны как на i (ака step ), так и на time

Файл step / time / Ax данных:

 $ cat match.dat  # Step Time Ax Ay Az Bx By Bz Cx Cy Cz Final  0 0.000 14.8032123290 0.0000000000 0.0000000000 0.0000000000 14.8032123290 0.0000000000 0.0000000000 0.0000000000 14.8032123290 3243.9033438318  1 0.500 14.8029498502 0.0000000000 0.0000000000 0.0000000000 14.8029498502 0.0000000000 0.0000000000 0.0000000000 14.8029498502 3243.7307919244  2 1.000 14.8026923814 0.0000000000 0.0000000000 0.0000000000 14.8026923814 0.0000000000 0.0000000000 0.0000000000 14.8026923814 3243.5615395313  3 1.500 14.8024398604 0.0000000000 0.0000000000 0.0000000000 14.8024398604 0.0000000000 0.0000000000 0.0000000000 14.8024398604 3243.3955453870  4 2.000 14.8021922354 0.0000000000 0.0000000000 0.0000000000 14.8021922354 0.0000000000 0.0000000000 0.0000000000 14.8021922354 3243.2327751298  100 50.000 14.8032123290 0.0000000000 0.0000000000 0.0000000000 14.8032123290 0.0000000000 0.0000000000 0.0000000000 14.8032123290 3243.9033438318  200 100.000 14.8029498502 0.0000000000 0.0000000000 0.0000000000 14.8029498502 0.0000000000 0.0000000000 0.0000000000 14.8029498502 3243.7307919244  300 150.000 14.8026923814 0.0000000000 0.0000000000 0.0000000000 14.8026923814 0.0000000000 0.0000000000 0.0000000000 14.8026923814 3243.5615395313  301 150.500 14.8024398604 0.0000000000 0.0000000000 0.0000000000 14.8024398604 0.0000000000 0.0000000000 0.0000000000 14.8024398604 3243.3955453870  400 200.000 14.8021922354 0.0000000000 0.0000000000 0.0000000000 14.8021922354 0.0000000000 0.0000000000 0.0000000000 14.8021922354 3243.2327751298  

Одна awk идея:

 awk ' FNR==NR { if (FNRgt;1) # skip header line in 1st file  Ax[$1 OFS $2]=$3 # use step   OFS   time as index for Ax[] array  next  }  $1 == "i" { gsub(/,/,"") # remove commas from line so we can use normal FS delimiter to pull ...  i=$3 # field #3 (i) and ...  time=$6 # field #6 (time)  if ( (i OFS time) in Ax) # if i   OFS   time is an index in Ax[] array ...  print i,time,Ax[i OFS time] # print our 3 values to stdout  } ' match.dat [0-9]*.xyz  

Это порождает:

 0 0.000 14.8032123290 100 50.000 14.8032123290 200 100.000 14.8029498502 300 150.000 14.8026923814 400 200.000 14.8021922354  

Если OP нуждается в выводе , отображаемом красивыми столбцами, одной из идей было бы передать результаты column , например:

 $ awk '...' match.dat [0-9]*.xyz | column -t 0 0.000 14.8032123290 100 50.000 14.8032123290 200 100.000 14.8029498502 300 150.000 14.8026923814 400 200.000 14.8021922354  

ПРИМЕЧАНИЕ: этот код соответствует точному совпадению строк символов; он не соответствует на основе числовых значений; поэтому 150 != 150.00

Комментарии:

1. отличные советы по форматированию и использованию символьных строк. Спасибо вам за то, что изо всех сил стараетесь помочь в этом.

Ответ №3:

Это может сработать для вас (GNU sed):

 sed -En '2~100s/^((s*S ){3}).*/1/p' file  

Включите расширенное регулярное выражение и отключите неявную печать -En .

Начиная со строки 2 (строка, следующая за заголовком), используйте модуль 100 для выбора необходимых строк, а затем команду подстановки, чтобы сохранить только первые три столбца.

Если вы должны использовать исходный файл для сопоставления, то:

 sed -En 's/^i =s*(S ),.*/s#^(\s*1(\s*\S ){2}).*#\1#p/p' file1of5 | sed -Enf - fileWithStep  

Это генерирует набор команд sed, который извлекает значения шагов и сопоставляет их с файлом со значениями шагов и извлекает только первые 3 столбца.

N. B. Пять файлов могут быть объединены или названы по отдельности в честь первого набора команд sed, т. е. заменить file1of5 на, file1 file2 file3 file4 file5 если они содержат уникальные значения шага.