Мне нравятся руководства TLDP http://tldp.org/guides.html
Существует все от Новичков Усовершенствованным руководствам Bash; это - как я учился так или иначе.
Если Ваши сегменты не действительно огромны (как в: Вы действительно не можете сэкономить так много RAM, по-видимому, потому что это - крошечная встроенная система, управляющая большой файловой системой), единственная передача является действительно лучшим подходом. Не только, потому что это будет быстрее, но и самое главное потому что это позволяет источнику быть потоком, от которого потеряно любое чтение данных и не сохраненное. Это - действительно задание для awk, хотя sed может сделать это также.
sed -n -e 's/^---$//' -e 't a' \
-e 'H' -e '$g' -e '$s/^\n//' -e '$p' -e 'b' \
-e ':a' -e 'h' # you are not expected to understand this
awk '{if (/^---$/) {chunk=""} # separator ==> start new chunk
else {chunk=chunk $0 RS}} # append line to chunk
END {printf "%s", chunk}' # print last chunk (without adding a newline)
Если необходимо использовать подход с двумя передачами, определите смещение строки последнего разделителя и печать от этого. Или определите байтовое смещение и печать от этого.
</input/file tail -n +$((1 + $(</input/file # print the last N lines, where N=…
grep -n -e '---' | # list separator line numbers
tail -n 1 | # take the last one
cut -d ':' -f 1) )) # retain only line number
</input/file tail -n +$(</input/file awk '/^---$/ {n=NR+1} END {print n}')
</input/file tail -c +$(</input/file LC_CTYPE=C awk '
{pos+=length($0 RS)} # pos contains the current byte offset in the file
/^---$/ {last=pos} # last contains the byte offset after the last separator
END {print last+1} # print characters from last (+1 because tail counts from 1)
')
Приложение: Если у Вас есть больше, чем POSIX, вот простая версия с одной передачей, которая полагается на общее расширение awk, который позволяет разделитель записей RS
быть регулярным выражением (POSIX только позволяет отдельный символ). Это не абсолютно корректно: если файл заканчивается разделителем записей, он печатает блок перед последним разделителем записей вместо пустой записи. Второе использование версии RT
избегает того дефекта, но RT
характерно для GNU awk.
awk -vRS='(^|\n)---+($|\n)' 'END{printf $0}'
gawk -vRS='(^|\n)---+($|\n)' 'END{if (RT == "") printf $0}'
Две стратегии передачи, кажется, правильная вещь. Вместо sed я использовал бы awk(1)
. Две передачи могли быть похожими на это:
$ LINE=`awk '/^---$/{n=NR}END{print n}' file`
получить номер строки. И затем повторите весь текст, начинающий с того номера строки с:
$ awk "NR>$LINE" file
Это не должно требовать чрезмерной буферизации.
awk -v line=$(awk '/^---$/{n=NR}END{print n}' file) 'NR>line' file
– glenn jackman
31.03.2011, 23:59
lnum=$(($(sed -n '/^---$/=' file | sed '$!d') +1)); sed -n "${lnum},$ p" file
Первое sed
номера строки ouputs "---" строк...
Второе sed
извлекает последнее число из вывода первого sed...
Добавьте 1 к тому числу для получения запуска "ccc" блока...
Третьи 'sed' выводы от запуска "ccc" блока к EOF
Обновление (с исправленным информационным ре методы Gilles)
Хорошо я был wondereing о как glenn jackman's tac
работал бы, таким образом, я испытанный три ответа (во время записи)... Тестовый файл (файлы) каждый содержал 1 миллион строк (их собственных номеров строки).
Все ответы сделали то, что ожидалось...
Вот времена..
Gilles sed
(единственная передача)
# real 0m0.470s
# user 0m0.448s
# sys 0m0.020s
Gilles awk
(единственная передача)
# very slow, but my data had a very large data block which awk needed to cache.
Gilles,' с двумя передачами' (первый метод)
# real 0m0.048s
# user 0m0.052s
# sys 0m0.008s
Gilles,' с двумя передачами' (второй метод)... очень быстро
# real 0m0.204s
# user 0m0.196s
# sys 0m0.008s
Gilles,' с двумя передачами' (третий метод)
# real 0m0.774s
# user 0m0.688s
# sys 0m0.012s
Gilles 'таращит глаза' (метод RT)... очень быстро, но не POSIX.
# real 0m0.221s
# user 0m0.200s
# sys 0m0.020s
glenn jackman... очень быстро, но не POSIX.
# real 0m0.022s
# user 0m0.000s
# sys 0m0.036s
fred.bear
# real 0m0.464s
# user 0m0.432s
# sys 0m0.052s
Mackie Messer
# real 0m0.856s
# user 0m0.832s
# sys 0m0.028s
Используйте "tac", который производит строки файла от конца до начала:
tac afile | awk '/---/ {exit} {print}' | tac
tac
не POSIX, это является определенным для Linux (это находится в GNU coreutils, и в некоторых busybox установках).
– Gilles 'SO- stop being evil'
31.03.2011, 21:54
Можно просто использоватьed
ed -s infile <<\IN
.t.
1,?===?d
$d
,p
q
IN
Как это работает:t
дублирует текущую(.
)строку -, которая всегда является последней строкой при запуске ed
(на тот случай, если разделитель присутствует в последней строке ), 1,?===?d
удаляет все строки до предыдущего совпадения включительно(ed
остается в последней строке )затем $d
удаляет (дубликат )последнюю строку, ,p
печатает текстовый буфер (заменить с w
для редактирования файла на месте )и, наконец, q
выход ed
.
Если вы знаете, что во входных данных есть хотя бы один разделитель (, и вам все равно, напечатан ли он ), тогда
sed 'H;/===/h;$!d;x' infile
будет короче.
Как это работает :добавляет все строки в H
старый буфер, перезаписывает h
старый буфер при обнаружении совпадения, d
удаляет все строки, кроме одной $
t, когда он x
изменяет буферы (и автопечатает ).
sed
хорошо работает, но я не могу добратьсяawk
пример для выполнения; это зависает..., и я получаю ошибку в 3-м примере:cut -f ':' -t 1
... сокращение: недопустимая опция - 't' – Peter.O 31.03.2011, 22:33cut
пример. Я ничего не вижу неправильно сawk
пример, какую версию awk Вы используете, и что вводится Ваш тест? – Gilles 'SO- stop being evil' 31.03.2011, 22:41awk
версия работает.. это - выступ, занимающий очень долгое время на большом файле..sed
версия обработала тот же файл в 0,470 с.. Мои данные тестирования очень взвешены... только два блока с одиноким '---' три строки от конца 1 миллиона строк... – Peter.O 31.03.2011, 22:51