У меня есть много больших (~ 30 МБ за штуку) текстовых файлов с разделителями табуляции и линиями переменной ширины. Я хочу извлечь 2-е поле из n-й (здесь n = 4) и следующей за последней строки (последняя строка пуста). Я могу получить их отдельно с помощью awk:
awk 'NR==4{print $2}' filename.dat
И (я не понимаю это полностью, но)
awk '{y=x "\n" $2};END{print y}' filename.dat
Но есть ли способ собрать их в один звонок? Мое более широкое намерение состоит в том, чтобы обернуть его в скрипт Python, чтобы собрать эти значения из большого количества файлов (многие тысячи) в отдельных каталогах, и я хочу уменьшить количество системных вызовов. Огромное спасибо -
Правка . Я знаю, что могу прочитать весь файл с помощью Python, чтобы извлечь эти значения, но я подумал, что awk может быть более подходящим для этой задачи (имея в виду одно из двух значений, расположенных в конце большой файл).
4 ответа
Вот как реализовать это в Python, не читая весь файл
Чтобы получить n-ю строку, у вас нет другого выбора, кроме как прочитать файл до n-й строки, поскольку строки имеют переменную ширину.
Чтобы получить строку со второй по последнюю, угадайте , какой длины строка может быть (быть щедрой), и найдите столько байтов до конца файла.
read()
с той точки, которую вы искали. Подсчитайте количество символов новой строки - вам нужно как минимум два. Если количество строк перевода меньше 2, удвойте свое предположение и попробуйте снова
Разделить данные, которые вы читаете на новые строки - строка, которую вы ищите, будет вторым последним элементом в разделении
Это мое решение в Python. Вдохновленный этим другим кодом:
def readfields(filename,nfromtop=3,nfrombottom=-2,fieldnum=1,blocksize=4096):
f = open(filename,'r')
out = ''
for i,line in enumerate(f):
if i==nfromtop:
out += line.split('\t')[fieldnum]+'\t'
break
f.seek(-blocksize,2)
out += str.split(f.read(blocksize),'\n')[nfrombottom].split('\t')[fieldnum]
return out
Когда я его профилировал, разница была на 0,09 секунды быстрее, чем решение, вызывающее awk (awk 'NR==4{print $2};{y=x $2};END{print y}' filename.dat
) с модулем подпроцесса. Не нарушитель соглашения, но когда остальная часть сценария написана на Python, кажется, что это выгодно (тем более, что у меня много этих файлов).
Вы можете передать количество строк в awk:
awk -v lines=$( wc -l < filename.dat ) -v n=4 '
NR == n || NR == lines-1 {print $2}
' filename.dat
Обратите внимание, что в команде wc
используйте перенаправление <
, чтобы избежать печати имени файла.
awk 'NR==4{print $2};{y=x "\n" $2};END{print y}' filename.dat
Похожие вопросы
Новые вопросы
python
Python - это многопарадигмальный, динамически типизированный, многоцелевой язык программирования. Он разработан для быстрого изучения, понимания и использования, а также для обеспечения чистого и единообразного синтаксиса. Обратите внимание, что Python 2 официально не поддерживается с 01.01.2020. Тем не менее, для вопросов о Python, связанных с версией, добавьте тег [python-2.7] или [python-3.x]. При использовании варианта Python (например, Jython, PyPy) или библиотеки (например, Pandas и NumPy) включите его в теги.