Реализуйте хвост с помощью awk - PullRequest
3 голосов
/ 01 февраля 2012

Хорошо, здесь я борюсь с этим кодом awk, который должен эмулировать команду tail

num=$1;
{
    vect[NR]=$0;

}
END{
    for(i=NR-num;i<=NR;i++)
            print vect[$i]
}

Так что я пытаюсь достичь здесь, это команда tail, эмулируемая awk, например, рассмотреть cat somefile |awk -f tail.awk 10 shoud напечатать последние 10 строк текстового файла, какие-либо предложения?

Ответы [ 4 ]

6 голосов
/ 13 октября 2015

Все эти ответы хранят исходный файл весь .Это ужасная идея, и она сломается для больших файлов.

Вот быстрый способ сохранить только количество строк, которые должны быть выведены (обратите внимание, что более эффективный tail всегда будет быстрее, потому что он не читаетвесь исходный файл!):

awk -vt=10 '{o[NR%t]=$0}END{i=(NR<t?0:NR);do print o[++i%t];while(i%t!=NR%t)}'

более разборчиво (и с меньшим кодом гольфа ):

awk -v tail=10 '
  {
    output[NR % tail] = $0
  }
  END {
    if(NR < tail) {
      i = 0
    } else {
      i = NR
    }
    do {
      i = (i + 1) % tail;
      print output[i]
    } while (i != NR % tail)
  }'

Объяснение разборчивого кода:

При этом используется оператор по модулю для хранения только нужного количества элементов (переменная tail).При разборе каждой строки она сохраняется поверх более старых значений массива (поэтому строка 11 сохраняется в output[1]).

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

Вы можете заменить строфу if / else (или троичное предложение в моем примере с игрой в гольф) просто с i = NR, если вам не нужны пустые строки для заполнения запрошенного числа (echo "foo" |awk -vt=10 … будет иметь девять пустых строк перед строкой "foo").

5 голосов
/ 01 февраля 2012
for(i=NR-num;i<=NR;i++)
    print vect[$i]

$ указывает позиционный параметр. Используйте просто i:

for(i=NR-num;i<=NR;i++)
    print vect[i]

Полный код, который работал для меня:

#!/usr/bin/awk -f
BEGIN{
        num=ARGV[1];
        # Make that arg empty so awk doesn't interpret it as a file name.
        ARGV[1] = "";
}
{
        vect[NR]=$0;
}
END{
        for(i=NR-num;i<=NR;i++)
                print vect[i]
}

Вы, вероятно, должны добавить некоторый код в END для обработки случая, когда NR <<code>num.

2 голосов
/ 02 февраля 2012

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

awk '{a=a b $0;b=RS;if(NR<=v)next;a=substr(a,index(a,RS)+1)}END{print a}' v=10
2 голосов
/ 01 февраля 2012

Вам необходимо добавить -v num=10 в командную строку awk, чтобы установить значение num. И начните с NR-num+1 в вашем последнем цикле, иначе вы получите num+1 строк вывода.

...