2014-02-14 4 views
1

У меня была проблема, решенная в предыдущем посте, используя awk, но теперь я хочу поставить цикл if, но я получаю сообщение об ошибке.Вставка, если цикл внутри awk

Вот проблема:

У меня было много файлов, которые выглядели так:

Header 
175566717.000 
175570730.000 
175590376.000 
175591966.000 
175608932.000 
175612924.000 
175614836.000 
. 
. 
. 
175680016.000 
175689679.000 
175695803.000 
175696330.000 

И я хотел, чтобы извлечь первые 2000 строк (строка 1 до 2000), а затем извлечь строки От 1500 до 3500, затем от 3000 до 5000 и т. Д. Я имею в виду: извлечение окна из 2000 строк с перекрытием 500 строк между непрерывными окнами до конца файла.

Это команда AWK используется для этого:

awk -v i=1 -v t=2000 -v d=501 'NR>1{a[NR-1]=$0}END{ 
    while(i<NR-1){ 
     ++n; 
     for(k=i;k<i+t;k++)print a[k] > "win"n".txt"; 
     close("_win"n".txt") 
     i=i+t-d 
    } 

}' myfile.txt 
done 

И я получаю несколько файлов с именами win1.txt, win2.txt, win3.txt и т.д ...

Моя проблема сейчас заключается в том, что, поскольку файл не был кратным 2000, мое последнее окно имеет менее 2000 строк. Как я могу поместить цикл if, который бы это сделал: если в последнем окне было меньше 2000 цифровых чисел, предыдущее окно должно было содержать все строки до конца файла.

ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ

Когда окна создаются, есть разрыв строки в end.That почему мне нужно, если петля учитывать окно менее 2000 цифровых номеров, а не только линии ,

+0

Быстро и грязно, было бы делать это впоследствии (вне 'awk', но в скрипте' bash'). Получите имена файлов из последних двух файлов, запустите 'wc' в последнем файле и примените ваш тест, если он меньше 2000' cat', это файл от второго до последнего. –

+0

Просто из любопытства, почему вы хотите совпадение между файлами?Удачи. – shellter

+0

@TimothyBrown спасибо, это может сработать. Я попробую это. – JM88

ответ

1

Если вы не должны использовать по какой-то другой причине, попробуйте подход

#!/bin/bash 
file="$(sed '/^\s*$/d' myfile.txt)" 
sed -n 1,2000p <<< "$file" 
first=1500 
last=3500 
max=$(wc -l <<< "$file" | awk '{print $1}') 
while [[ $max -ge 2000 && $last -lt $((max+1500)) ]]; do 
    sed -n "$first","$last"p <<< "$file" 
    ((first+=1500)) 
    ((last+=1500)) 
done 

Очевидно, что это будет менее быстрым, чем и больше ошибок, склонной к gigatic файлов, но должен работать в большинстве случаев.

+0

Но это будет порождать sed 1 + N раз, в отличие от нереста awk один раз. – kojiro

+0

Где N = # _ of_lines/2000, конечно. Не сказал [tag: sed] будет быстрее, чем [tag: awk] – BroSlow

+0

Зачем читать файл в памяти? Вместо использования '<<<" $ file "' для чтения из строки, просто читайте из файла каждый раз. ОС будет кэшировать файл в памяти, а также вашу программу, поэтому не должно быть заметной разницы в производительности. –

1

Изменение while условие, чтобы сделать его остановить раньше:

while (i+t <= NR) { 

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

for (k = i; k < (i+t+t-d <= NR ? i+t : NR); k++) 

Остальная часть ваш код может оставаться неизменным; хотя я взял на себя смелость снять заявление close (почему это было?) и установить d=500, чтобы сделать выходные файлы действительно перекрытием на 500 строк.

awk -v i=1 -v t=2000 -v d=500 'NR>1{a[NR-1]=$0}END{ 
    while (i+t <= NR) { 
     ++n; 
     for (k=i; k < (i+t+t-d <= NR ? i+t : NR); k++) print a[k] > "win"n".txt"; 
     i=i+t-d 
    } 
}' myfile.txt 

Я тестировал его с малыми значениями t и d, и это похоже на работу в соответствии с просьбой.

Последнее замечание: для больших файлов ввода я бы не стал рекомендовать хранить все это в массиве a.

Смежные вопросы