Печать новой строки с помощью awk

Печать новой строки с помощью awk

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

Name: w

Age: x

Height: y

Weight: z

Мне нужны только возраст, рост и вес, поэтому я сначала ввел:

grep -E 'Age|Height|Weight' [input file] > output.txt

Из-за количества файлов мой вывод теперь выглядит так:

Age 1
 
Height 1

Weight 1

Age 2

Height 2

Weight 2

etc...

Теперь я хочу запустить скрипт awk, чтобы он прошел по моему новому файлу output.txt и сначала нашел каждую строку со словом 'Age' и вывел ее. После того, как он сделал все строки со словом 'Age', он затем вычисляет высоту и вес. Я запустил скрипт:

awk -F"\t" '/Age/ {print} /Height/ {print}' output.txt >output2.txt

Но если просто печатает его как исходный выходной файл. Как мне изменить его так, чтобы после того, как он сделал все Возрастные, он затем нашел Ростовые?

РЕДАКТИРОВАТЬ:

Мой желаемый результат — это файл

Возраст 1

Возраст 2

Высота 1

Высота 2

Вес 1

Вес 2

и т. д..

Для ясности: Возраст 1 — это строка с надписью «возраст» из файла 1 и т. д.

решение1

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

BEGIN {
    AgeIndex = 1
    HeightIndex = 1
}
/Age/ {
    ages[AgeIndex] = $0
    AgeIndex+=1
}
/Height/ {
    heights[HeightIndex] = $0
    HeightIndex+=1
}
END {
    for (x = 1; x < AgeIndex; x++)
        print ages[x] "\n"
    for (x = 1; x < HeightIndex; x++)
        print heights[x] "\n"
}

Сохраните это, скажем, в filter.awkи затем запустите:

awk -f filter.awk output.txt > output2.txt

чтобы получить желаемый результат:

$ awk -f filter.awk < data
Age 1

Age 2

Height 1

Height 2

Мы делаем два массива agesи heightsсохраняем в них каждую соответствующую строку по мере продвижения. AgeIndexсодержит, насколько далеко мы продвинулись по массиву. В конце мы выводим каждую сохраненную строку (и дополнительную новую строку, как вы хотите), сначала все возрасты, затем все высоты.

Массивы будут хранить весь файл в памяти к концу, поэтому если ваш файл особенно большой, вам придется пожертвовать этим использованием памяти ради времени, которое потребуется, чтобы пройти по всему файлу больше одного раза. На этом этапе это по сути то же самое, что и программа на любом другом языке — если у вас нет особых причин использовать awk, вы можете предпочесть другой язык. Честно говоря, я думаю, что я бы рекомендовал это — awk здесь не покупает много.

решение2

С gawk:

$ awk -F"\t" '
    { a[$1]++ }
    END {
        n = asorti(a,b);
        for (i = 1; i <= n; i++) {
            print b[i];
            if (i%2 == 0) {
                printf "\n";
            }
        }
    }
' output.txt
Age 1
Age 2

Height 1
Height 2

Weight 1
Weight 2

решение3

Я предполагаю, что пустые строки не являются частью вашего фактического файла, или, по крайней мере, вас это не волнует. Если так, то все, что вам нужно, это sort:

$ cat output.txt
Age 1
Height 1
Weight 1
Age 2
Height 2
Weight 2

$ sort output.txt
Age 1
Age 2
Height 1
Height 2
Weight 1
Weight 2

Однако, если ваши файлы не слишком велики для хранения в памяти, может быть проще сделать все за один шаг:

grep -whE 'Age|Height|Weight' *txt | sort > outfile

Вышеуказанный код будет искать Ageили Heightили Weightво всех файлах, имена которых заканчиваются на txtв текущем каталоге ( *txt). -wОзначает «соответствовать только целым словам» (чтобы, например, Ageне совпадало ), необходим, поскольку без него имя файла печатается вместе с соответствующей строкой, когда указано более одного входного файла. Включает расширенные регулярные выражения, что дает нам для OR.Ageing-h-E|

ПРИМЕЧАНИЕ: Если по какой-то причине вам действительно нужна дополнительная пустая строка между каждой записью (а это не то, что grepсоздаст ваша команда), вы можете добавить ее с помощью:

grep -whE 'Age|Height|Weight' *txt | sort | sed 's/$/\n/'

Пример

$ for i in {1..3}; do echo -e "Name $i\nAge $i\nHeight $i\nWeight $i" > $i.txt; done
$ for f in *txt; do echo " -- $f --"; cat $f; done
 -- 1.txt --
Name 1
Age 1
Height 1
Weight 1
 -- 2.txt --
Name 2
Age 2
Height 2
Weight 2
 -- 3.txt --
Name 3
Age 3
Height 3
Weight 3

$ grep -whE 'Age|Height|Weight' *txt | sort
Age 1
Age 2
Age 3
Height 1
Height 2
Height 3
Weight 1
Weight 2
Weight 3

В любом случае, даже если sortэто вас не устроит, я бы сделал вот так на Perl awk(предполагая, что вам нужны дополнительные пустые строки, что, опять же, вам, скорее всего, не нужно):

$ perl -ane '$k{$F[0]}.=$_."\n" if /./; 
    END{print $k{$_},"\n" for sort keys (%k)}' output.txt 
Age 1

Age 2


Height 1

Height 2


Weight 1

Weight 2


 

Вы можете пропустить это, head -n -2чтобы избавиться от последних двух пустых строк, если они вам не нужны.

решение4

pythonрешение этой проблемы:

from collections import defaultdict
f = open("output.txt", "r")
d = defaultdict(list)
for line in f:
   line = line.strip()
   if line != '':
     arr = line.split(" ")
     d[arr[0]].append(arr[1])
print d.items()

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

Связанный контент