Проверьте свои настройки выделенного дискового пространства согласно следующему официальному Debian HowTo.
Существует множество причин, по которым чтение всего файла в пространство шаблонов может пойти не так. Логическая проблема в вопросе, окружающем последнюю строку, является общей. Это связано со строковым циклом sed
- когда строк больше нет и sed
встречает EOF, он проходит - обработка прекращается. Итак, если вы находитесь на последней строчке и даете команду sed
получить другую, она остановится прямо здесь и больше ничего не сделает.
Тем не менее, если вам действительно нужно прочитать весь файл в пространстве шаблонов, то, вероятно, в любом случае стоит подумать о другом инструменте. Дело в том, что sed
одноименный редактор потока - он предназначен для работы с строкой или логическим блоком данных - за раз.
Есть много подобных инструментов, которые лучше приспособлены для обработки полных файловых блоков. ed
и ex
, например, могут делать многое из того, что может sed
, и с аналогичным синтаксисом - и многое другое - но вместо того, чтобы работать только с входной поток, преобразуя его в выходной, как это делает sed
, они также поддерживают временные файлы резервных копий в файловой системе. Их работа по мере необходимости буферизуется на диск, и они не завершаются внезапно в конце файла (и имеют тенденцию намного реже взламываться при нагрузке на буфер) . Более того, они предлагают множество полезных функций, которых нет в sed
- из тех, которые просто не имеют смысла в контексте потока - таких как отметки строк, отмена, именованные буферы, соединение и многое другое. Основное преимущество
sed
- это его способность обрабатывать данные сразу после их чтения - быстро, эффективно и в потоке. Когда вы проглатываете файл, вы выбрасываете его и , вы, как правило, сталкиваетесь с трудностями крайнего случая, такими как проблема последней строки, которую вы упомянули, переполнение буфера и ужасная производительность - по мере того, как данные, которые он анализирует, становятся длиннее регулярного выражения время обработки движком при перечислении совпадений увеличивается экспоненциально .
Что касается последнего пункта, кстати: хотя я понимаю, что пример s / a / A / g
, скорее всего, всего лишь наивный пример и, вероятно, не тот сценарий, который вы хотите собрать в вход для, возможно, вам стоит ознакомиться с y ///
.Если вы часто обнаруживаете, что g
локально заменяете один символ другим, то y
может быть очень полезным для вас. Это преобразование, в отличие от подстановки, и оно намного быстрее, поскольку не подразумевает регулярное выражение. Этот последний момент также может быть полезен при попытке сохранить и повторить пустые адреса //
, потому что это не влияет на них, но может быть затронуто ими. В любом случае, y / a / A /
является более простым средством достижения того же самого - и возможны также свопы, например: y / aA / Aa /
, который поменял бы все верхний / нижний регистр, как в строке друг для друга.
Вы также должны заметить, что описываемое вами поведение на самом деле не является тем, что должно происходить в любом случае.
Из информации GNU sed
в разделе ОБЫЧНО СООБЩАЕМЫЕ ОБ ОШИБКАХ :
N
команда в последней строке
Большинство версий sed
выйти без печати, когда команда N
введена в последней строке файла. GNU sed
печатает пространство шаблонов перед выходом, если, конечно, не указан командный переключатель -n
. Этот выбор сделан намеренно.
Например, поведение sed N foo bar
будет зависеть от того, четное или нечетное количество строк в foo.Или при написании сценария для чтения следующих нескольких строк после сопоставления с образцом традиционные реализации sed
заставят вас написать что-то вроде / foo / {$! N; $! N; $! N; $! N; $! N; $! N; $! N; $! N; $! N}
вместо просто / foo / {N; N; N; N; N; N; N; N; N; }
.
В любом случае, самый простой обходной путь - использовать $ d; N
в сценариях, основанных на традиционном поведении, или установить для переменной POSIXLY_CORRECT
непустое значение. .
Переменная среды POSIXLY_CORRECT
упоминается, потому что POSIX указывает, что если sed
встречает EOF при попытке N
, он должен выйти без вывода,но версия GNU в этом случае намеренно порывает со стандартом. Также обратите внимание, что даже если поведение оправдано выше, предполагается, что случай ошибки связан с потоковым редактированием, а не с захватом всего файла в память.
Стандарт определяет поведение N
следующим образом:
N
Добавить следующую строку ввода за вычетом ее завершающей \ n
ewline , в пространство шаблона, используя встроенную \ n
прямую линию, чтобы отделить добавленный материал от исходного материала. Обратите внимание, что текущий номер строки изменится.
Если следующая строка ввода недоступна, команда N
должна перейти в конец сценария и завершить работу без запуска нового цикла или копирования пространства шаблонов в стандартный вывод.
В связи с этим есть некоторые другие GNU-измы, продемонстрированные в вопросе - в частности, использование метки :
, b
ранчо и {
скобки контекстной функции }
. Как показывает практика, любая команда sed
, которая принимает произвольный параметр, понимается как ограничивающая в сценарии \ n
ewline. Таким образом, все команды ...
:arbitrary_label_name; ...
b to_arbitrary_label_name; ...
//{ do arbitrary list of commands } ...
... с большой вероятностью будут работать беспорядочно в зависимости от реализации sed
, которая их читает. Переносно их следует записать:
...;:arbitrary_label_name
...;b to_arbitrary_label_name
//{ do arbitrary list of commands
}
То же самое верно для r
, w
, t
, a
, i
и c
(и, возможно, еще несколько, о которых я сейчас забыл) .Почти в каждом случае они также могут быть записаны:
sed -e :arbitrary_label_name -e b\ to_arbitary_label_name -e \
"//{ do arbitrary list of commands" -e \}
... где новый оператор -e
xecution заменяет разделитель строки \ n
. Итак, если текст GNU info
предлагает традиционную реализацию sed
, вы должны будете сделать :
/foo/{ $!N; $!N; $!N; $!N; $!N; $!N; $!N; $!N; $!N }
... скорее, это должно быть ...
/foo/{ $!N; $!N; $!N; $!N; $!N; $!N; $!N; $!N; $!N
}
] ... конечно, это тоже неправда. Писать сценарий таким образом немного глупо. Есть гораздо более простые способы сделать то же самое, например:
printf %s\\n foo . . . . . . |
sed -ne 'H;/foo/h;x;//s/\n/&/3p;tnd
//!g;x;$!d;:nd' -e 'l;$a\' \
-e 'this is the last line'
... который печатает:
foo
.
.
.
foo\n.\n.\n.$
.$
this is the last line
... потому что команда t
est - как и большинство команд sed
- зависит от линейного цикла для обновления своего регистра возврата, и здесь линейному циклу разрешается выполнять большую часть работы. Это еще один компромисс, который вы делаете, когда проглатываете файл - цикл строки больше не обновляется, и многие тесты будут вести себя ненормально.
Вышеупомянутая команда не рискует выйти за пределы ввода, потому что она просто выполняет несколько простых тестов, чтобы проверить, что она читает, когда читает. С H
old все строки добавляются в удерживаемое пространство, но если строка соответствует / foo /
, она перезаписывает h
старое пространство. Затем буферы изменяются e x
, и выполняется попытка условной замены s ///
, если содержимое буфера совпадает с последним адресованным шаблоном //
. Другими словами, // s / \ n / & / 3p
пытается заменить третью новую строку в удерживаемом пространстве на себя и распечатать результаты , если удерживаемое пространство в настоящее время совпадает с / foo /
.Если это t
будет успешным, скрипт перейдет к метке n
ot d
elete - что делает l
ook и завершает сценарий .
В случае, если и / foo /
, и третья новая строка не могут быть сопоставлены вместе в удерживаемом пространстве, тогда //! G
перезапишет буфер, если / foo /
не соответствует, или, если он совпадает, он перезапишет буфер, если \ n
ewline не соответствует (тем самым заменяя / foo /
с собой) . Этот небольшой тонкий тест предотвращает ненужное заполнение буфера на длинных отрезках no / foo /
и гарантирует, что процесс остается быстрым, потому что ввод не накапливается. В случае отказа no / foo /
или // s / \ n / & / 3p
буферы снова меняются местами, и каждая строка, кроме последней, там удаляется.
Эта последняя - последняя строка $! D
- это простая демонстрация того, как нисходящий sed
скрипт можно заставить легко обрабатывать несколько случаев. Когда ваш общий метод состоит в том, чтобы отсечь нежелательные случаи, начиная с самых общих и работая над наиболее конкретными, тогда крайние случаи могут быть более легко обработаны, потому что им просто разрешено пропадать до конца скрипта с другими вашими требуемыми данными и когда все это завершает вас, у вас остаются только те данные, которые вам нужны. Однако необходимость извлекать такие крайние случаи из замкнутого цикла может быть намного сложнее.
И вот последнее, что я должен сказать: если вы действительно должны вытащить весь файл, тогда вы можете сделать немного меньше работы, полагаясь на линейный цикл, который сделает это за вас. Обычно вы должны использовать N
ext и n
ext для просмотра вперед -потому что они продвигаются вперед линейного цикла. Вместо избыточной реализации замкнутого цикла внутри цикла - поскольку линейный цикл sed
в любом случае является простым циклом чтения - если ваша цель состоит только в беспорядочном сборе входных данных, то, вероятно, это проще сделать:
sed 'H;1h;$!d;x;...'
... который соберет весь файл или провалит попытку.
примечание о N
и поведении последней строки ...
хотя у меня нет доступных инструментов для тестирования, считаю, что
N
при чтении и на месте редактирование ведет себя по-разному, если редактируемый файл является файлом сценария для следующего чтения.
Это не удается, потому что команда n
приходит перед матчем шаблона $!
(не последняя строка) и SED-Quits, прежде чем делать любую работу:
n
Добавьте новую строку в пространство шаблона, затем добавьте следующую строку ввода в пространство шаблона. Если больше нет ввода, а затем SED выходит без обработки больше команд .
Это может быть легко закреплено для работы с однострочным входом, а также (и, действительно, более четко в любом случае), просто группируя команды n
и B
после Узор:
sed ':a;$!{N;ba}; [commands...]'
Это работает следующим образом:
: A
Создайте ярлык с именем «A» $!
Если не последняя строка, то n
добавляют следующую строку на шаблон (или выйти, если нет следующей строки)
И BA
BA ветвь (перейдите к) метку «A» , к сожалению, это не портативно (поскольку он опирается на расширения GNU), но следующая альтернатива (предложенная @Mikeserv) является портативным:
sed 'H;1h;$!d;x; [commands...]'
Как исчерпывающе объясняет @mikeserv, N не подходит для этого.
Этот фрагмент будет аккумулировать весь файл, и вы сможете использовать его как префикс к остальной части скрипта:
H;$!d;x;s/^\n//
Он использует H для накопления файла, пока не будет прочитана последняя строка
Пример использования *протестирован с GNU sed ), обратите внимание на отсутствие завершающего \n:
$ printf 'a\nb\nc' | sed -e 'H;$!d;x;s/^\n//' -e 's/^/[/;s/$/]/'
[a
b
c]$ echo $?
0