2016-12-03 4 views
3

У меня есть файл настроить какAWK печати Предпоследняя запись файла

Words on 
many line 
% 
More Words 
on many lines 
% 
Even More Words 
on many lines 
% 

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

Я использовал:

awk -v RS=\% ' END{ print NR }' $f 

найти число записей (1136). Тогда я сделал

awk -v RS=\% ' { print $(NR-1) }' $f 

и

awk -v RS=\% ' { print $(NR=1135) }' $f 

. Ни один из них не работал, а вместо этого отображал запись в начале файла и множество пустых строк. ВЫВОД:

"You know, of course, that the Tasmanians, who never committed adultery, are 
now extinct." 
    -- M. Somerset Maugham 


"The 
is 
what 
that 


Этот вывод имел много, много больше пустых строк и содержит запись около середины файла.

awk -v RS=\% 'END{ print $(NR-1) }' $f 

возвращает пустую строку. Эта же команда с разными значениями $(NR-x) также возвращает пустую строку.

Может ли кто-нибудь помочь мне распечатать вторую по последней записи в этом случае? Спасибо

+1

'$ n' выбирает _field_; чтобы выбрать _record_ (обычно, но не здесь), используйте 'awk -vRS =% 'NR == 1135'' для одного файла или комбинированных файлов или' FNR' для одного из нескольких файлов. Вы можете сделать оба прохода за один проход, например, 'awk -vRS =% 'FNR == NR {sel = NR-1} FNR == sel' filename filename'. Но лучше использовать @ dawg один проход с двумя варами. –

ответ

3

Вы можете сделать:

awk '{this=last;last=$0} END{print this}' file 

Или, если вы не против, весь файл в память:

awk '{a[NR]=$0} END{print a[NR-1]}' file 

Или, если это только подсчет строк (или количество записей), вы можете сохранить скользящее удаление, чтобы вы не были слишком свинчивыми в памяти:

$ seq 999999 | tail -2 
999998 
999999 
$ seq 999999 | awk '{a[NR]=$0; delete a[NR-3]} END{print a[NR-1]}' 
999998 

Если они являются блоками текста, тот же метод работает, если вы можете разделить блоки на разделительные записи.

Дано:

$ echo "$txt" 
Words on 
many line 
% 
More Words 
on many lines 
% 
Even More Words 
on many lines 
% 

Вы можете сделать:

$ echo "$txt" | awk -v RS=\% '{a[NR]=$0} END{print a[NR-1]}' 

Even More Words 
on many lines 

$ echo "$txt" | awk -v RS=\% '{a[NR]=$0} END{print a[NR-2]}' 

More Words 
on many lines 

Если вы хотите, чтобы не печатать передней и задней \n вы можете сделать:

$ echo "$txt" | awk 'BEGIN{RS="%\n"} {a[NR]=$0} END{printf a[NR-2]}' 
Words on 
many line 

Наконец, если вы знать конкретную запись, которую вы хотите распечатать, сделать это в awk:

$ seq 999999 | awk -v mrk=1135 'NR==mrk{print; exit}' 
1135 

Если вы хотите случайную запись, вы можете сделать:

$ awk -v min=1 -v max=1135 'BEGIN{srand() 
            RS="%\n" 
            tgt=int(min+rand()*(max-min+1)) 
            } 
          NR==tgt{print; exit}' file 
+0

Похоже, это приближается, но запись может состоять из любого количества строк. Есть несколько записей с 1 строкой и несколькими записями со 100 строками. – Angelo

+0

Просто установите 'RS' надлежащим образом, и он должен работать ... – dawg

+0

Что делать, если бы я хотел, а вместо второй записи записывать случайную запись? То есть, выведите запись где-нибудь между 1 и 1135? – Angelo

1

Должно ли решение быть с awk? Просто использование головы и хвоста было бы проще.

tail -2 file.txt | head 1 > justthatline.txt 
+0

Не будет ли это 'tail -2 file.txt | head -n 1'? Это творческий подход, но вам не хватает аргумента '-n' для' head' – dawg

+0

, это не отдельные строки, количество строк в каждой записи может варьироваться от 1 до 100 строк. – Angelo

+0

Как насчет 'tac-файла? sed | tac' ... lol – EvansWinner

0

Лучшим способом для этого было бы использовать Бегин конструкцию.

awk 'BEGIN{RS="%\n"; ORS="%\n"}(NR>=2){print}' file 

RS и ORS устанавливают разделители входных файлов и выходных записей соответственно.

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