sed: удаление \r\r перед \n в очень большом файле
У меня есть поврежденный файл образа диска (около 27 ГБ), в который были вставлены все символы \ n \ r \ r. Я хочу удалить эти \ r \ r раньше всех \ n.
Я пробовал с awk:
awk '{ sub("\r\r$", ""); print }' mangled.raw > image.raw
Но файл кажется слишком большим: "awk: ошибка времени выполнения: нехватка памяти"
Я тоже попробовал с sed:
sed 's/\r\r$//g' mangled.raw > image.raw
Но здесь выходной файл кажется неполным: его размер составляет всего 20 ГБ, а конец mangled.raw содержит много нулевых символов, а конец image.raw содержит содержимое файла. Каким-то образом sed, кажется, останавливается до конца.
Есть идеи, как это сделать правильно?
1 ответ
Комментарий старейшины может быть правильным - это зависит от того, как произошла коррупция. Если бы это было эквивалентно s/\n/\r\r\n/
тогда это обратимо, но если это было s/\r*\n/\r\r\n/
тогда это не так.
В любом случае я бы использовал Perl для чего-то вроде этого. В отличие от sed, он с самого начала был разработан для работы со строками, которые очень длинные и могут содержать NUL и другие нетекстовые символы.
perl -pe 's/\r\r\n/\n/g' mangled.raw > image.raw
Это может занять много памяти, так как он все еще читает файл как последовательность строк, и могут быть большие сегменты файла без \n
это будет рассматриваться как одна "линия". Но если вы читаете его по блокам, вы должны быть осторожны, чтобы не пропустить \r\r\n
последовательность, которая охватывает границу блока. Как это:
perl -e '
$/=\65536;
while(<>) {
if(/\r\z/) {
if(length($nextblock=<>)) {
$_.=$nextblock;
redo;
}
}
s/\r\r\n/\n/g;
print;
}
' mangled.raw > image.raw
Редактировать: я понял, что приведенный выше код застрянет в бесконечном цикле, если последний байт ввода был \r
, Он был обновлен для правильной обработки этого случая.
Изменить 2: однострочник Perl содержал неправильный символ замены. Это было обновлено.