Реализовать хвост с помощью awk

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

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

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


person Lucian Enache    schedule 01.02.2012    source источник
comment
awk -f tail.awk num=10, 10 сами по себе будут интерпретироваться как имя файла. Удачи.   -  person shellter    schedule 01.02.2012
comment
Вам действительно нужно хранить весь файл?   -  person Johnsyweb    schedule 01.02.2012
comment
@Johnsyweb, ну нет, но я думал использовать именно этот подход, есть другие идеи? не поленился опубликовать их :)   -  person Lucian Enache    schedule 01.02.2012
comment
Поскольку вы явно делаете это как упражнение, любой код, который я публикую, вам не поможет.   -  person Johnsyweb    schedule 01.02.2012
comment
Это не был вопрос, который я получил сегодня на экзамене по операционным системам, мне просто было любопытно, есть ли другие жизнеспособные альтернативы   -  person Lucian Enache    schedule 01.02.2012


Ответы (4)


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 для обработки случая, когда NRnum.

person Kevin    schedule 01.02.2012
comment
когда я пытаюсь преобразовать текстовый файл в awk, я все равно получаю сообщение об ошибке на ARGV[1] ---------------- ----------------------------- cat test1.txt | awk -f тайлаук 10 - person Lucian Enache; 01.02.2012
comment
учтите, что я добавил BEGIN{num=ARGV[1]} - person Lucian Enache; 01.02.2012

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

Вот быстрый способ сохранить только количество выводимых строк (обратите внимание, что более эффективный 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»).

person Adam Katz    schedule 13.10.2015

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

person Lars Kotthoff    schedule 01.02.2012
comment
Да, спасибо, я забыл увеличить nr-num, поскольку я пытался выполнить обратное чтение с nr на nr-num, поменял местами индексы и забыл увеличить, в любом случае спасибо - person Lucian Enache; 01.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
person potong    schedule 02.02.2012
comment
Я бы проголосовал за это, если бы это было объяснено. Я могу это понять, но это требует объяснения для всех. - person Camusensei; 23.09.2015