Из-за ошибки приложения, которая еще не диагностирована, у меня есть несколько сотен серверов с полным диском. Есть один файл, который был заполнен дублирующимися строками - не файл журнала, а файл пользовательской среды с определениями переменных (поэтому я не могу просто удалить этот файл).
Я написал простую sed
команду, чтобы проверить ошибочно добавленные строки и удалить их, и протестировал их на локальной копии файла. Это сработало как задумано.
Однако, когда я попробовал его на сервере с полным диском, я получил примерно следующую ошибку (это из памяти, а не копировать и вставлять):
sed: couldn't flush /path/to/file/sed8923ABC: No space left on deviceServerHostname
Конечно, я знаю, что места не осталось. Вот почему я пытаюсь удалить материал! (Команда, sed
которую я использую, уменьшит размер файла 4000+ примерно до 90 строк.)
Моя sed
команда простоsed -i '/myregex/d' /path/to/file/filename
Есть ли способ применить эту команду, несмотря на полный диск?
(Это должно быть автоматизировано, поскольку мне нужно быстро применить его к нескольким сотням серверов.)
(Очевидно, что ошибка приложения должна быть диагностирована, но в то же время серверы работают неправильно ....)
Обновление: Ситуация, с которой я столкнулся, была разрешена путем удаления чего-то еще, что я мог удалить, но мне все еще хотелось бы получить ответ на этот вопрос, который будет полезен в будущем и для других людей.
/tmp
это не ходят; это в той же файловой системе.
Прежде чем освободить место на диске, я проверил и обнаружил, что могу удалить строки vi
, открыв файл и запустив его, :g/myregex/d
а затем успешно сохранив изменения с помощью :wq
. Похоже, можно автоматизировать это, не прибегая к отдельной файловой системе для хранения временного файла .... (?)
источник
sed -i
создает временную копию для работы. Я подозреваю, чтоed
было бы лучше для этого, хотя я не достаточно знаком, чтобы назначить фактическое решениеed
вы запустите:printf %s\\n g/myregex/d w q | ed -s infile
но имейте в виду, что некоторые реализации также используют временные файлы, какsed
(вы можете попробовать busybox ed - afaik, он не создает временный файл)echo
. использоватьprintf
. иsed
добавьте несколько символов, которые вы уронили в последнюю строку, чтобы избежать потери пробелов. Кроме того, ваша оболочка должна иметь возможность обрабатывать весь файл в одной командной строке. это твой риск - сначала проверь.bash
особенно плохо в этом (я думаю, что это делать с пространством стека?) и может надоесть вам в любое время. дваsed
рекомендованных si будут по крайней мере использовать буфер канала ядра для хорошего эффекта между ними, но метод довольно похож. ваша команда sub будет также усекатьfile
, успешно ли sed w / in.sed '/regex/!H;$!d;x' <file|{ read v && cat >file;}
и если это сработает, прочитайте остаток моего ответа.Ответы:
-i
Вариант не очень перезаписать исходный файл. Он создает новый файл с выводом, а затем переименовывает его в исходное имя файла. Поскольку у вас нет места в файловой системе для этого нового файла, он завершается ошибкой.Вам нужно будет сделать это самостоятельно в своем скрипте, но создать новый файл в другой файловой системе.
Кроме того, если вы просто удаляете строки, которые соответствуют регулярному выражению, вы можете использовать
grep
вместоsed
.Как правило, программы редко могут использовать один и тот же файл для ввода и вывода - как только он начинает запись в файл, часть программы, которая читает из файла, больше не будет видеть исходное содержимое. Поэтому он должен сначала скопировать оригинальный файл куда-нибудь, либо записать в новый файл и переименовать его, когда это будет сделано.
Если вы не хотите использовать временный файл, вы можете попробовать кэшировать содержимое файла в памяти:
источник
rsync -a --no-owner --no-group --remove-source-files "$backupfile" "$destination"
от сюдаsed -i
это сохраняет?sed -i
не сохраняет ничего из этого. Я просто попытался сделать это с файлом, который мне не принадлежит, но находится в каталоге, которым я владею, и он позволил мне заменить файл. Замена принадлежит мне, а не первоначальному владельцу.var=$(< FILE); echo "$FILE" | grep '^"' > FILE
v=$(<file)&& printf %s\\n "$v" >file
но вы даже не использовать&&
. Аскер говорит о запуске его в сценарии - автоматизации перезаписи файла частью себя. Вы должны по крайней мере подтвердить, что вы можете успешно открыть ввод и вывод. Также оболочка может взорваться.Вот как это
sed
работает. При использовании с-i
(на месте редактирования)sed
создает временный файл с новым содержимым обработанного файла. По окончанииsed
заменяет текущий рабочий файл временным. Утилита не редактирует файл на месте . Это точное поведение каждого редактора.Это похоже на выполнение следующей задачи в оболочке:
В этот момент
sed
пытается сбросить буферизованные данные в файл, указанный в сообщении об ошибке, с помощьюfflush()
системного вызова:Для вашей проблемы я вижу решение в монтировании отдельной файловой системы (например, a
tmpfs
, если у вас достаточно памяти или внешнего устройства хранения данных) и перемещении туда некоторых файлов, их обработке и перемещении назад.источник
С момента публикации этого вопроса я узнал, что
ex
это POSIX-совместимая программа. Это почти универсальная символическая ссылкаvim
, но в любом случае следующее (я думаю) является ключевым моментомex
в отношении файловых систем (взято из спецификации POSIX):«... повлияет на любой файл ...» Я считаю, что помещение чего-либо в файловую систему (вообще, временный файл) будет считаться «воздействием на любой файл». Может быть?*
Тщательное изучение спецификаций POSIX для
ex
указания некоторых «ошибок» в отношении его предполагаемого переносимого использования по сравнению с обычными сценариями использованияex
найденных в сети (которые усеяны специальнымиvim
командами).+cmd
является необязательной в соответствии с POSIX.-c
вариантов также необязательно.:g
«съедает» все до следующей неэкранированной новой строки (и, следовательно, запускает ее после каждого совпадения, найденного для регулярного выражения, а не один раз в конце). Таким образом,-c 'g/regex/d | x'
удаляется только один экземпляр, а затем выходит из файла.Итак, в соответствии с тем, что я исследовал, POSIX-совместимый метод для редактирования на месте файла в полной файловой системе для удаления всех строк, соответствующих определенному регулярному выражению:
Это должно работать, если у вас достаточно памяти для загрузки файла в буфер.
* Если вы найдете что-то, что указывает на обратное, пожалуйста, укажите это в комментариях.
источник
ex +g/match/d -scx file
, POSIX-совместимый?vi
работало на полной файловой системе, я считаю, что в большинстве случаев оно также будет работать,ex
хотя, возможно, не для огромного файла.sed -i
не работает на полной файловой системе независимо от размера файла.Используй трубу, Люк!
Читать файл | фильтр | написать обратно
в этом случае
sed
не создает новый файл, а просто отправляет вывод по каналу, вdd
котором открывается тот же файл . Конечно, можно использоватьgrep
в конкретном случаезатем обрежьте оставшиеся.
источник
sed
всегда использует временные файлы?grep
во всяком случае не будетsponge
команде. Да,sed
с-i
lilke всегда создает файлы "seduyUdmw" с 000 прав.Как отмечалось в других ответах,
sed -i
работает, копируя файл в новый файл в том же каталоге , внося изменения в процесс, а затем перемещая новый файл поверх оригинала. Вот почему это не работает.ed
(оригинальный редактор строк) работает в некотором роде, но, в прошлый раз, когда я проверял, он использует/tmp
файл с нулями. Если ваша/tmp
файловая система отличается от той, которая заполнена,ed
возможно, эта работа за вас.Попробуйте это (в приглашении вашей интерактивной оболочки):
P
(Который является столицей P) не является строго необходимым. Включает подсказку; без этого вы работаете в темноте, и некоторые люди находят это сбивающим с толку.w
Иq
являются ж обрядовым и д ПИФ.Если ваш
/tmp
каталог находится в файловой системе, которая заполнена (или если его файловая система также заполнена), попробуйте найти где-нибудь место. хаос упомянул монтирование tmpfs или внешнего запоминающего устройства (например, флешки); но если у вас есть несколько файловых систем, и они не все заполнены, вы можете просто использовать одну из других существующих. хаос предлагает скопировать файл (ы) в другую файловую систему, отредактировать их там (с помощьюsed
) и затем скопировать обратно. На данный момент, это может быть самым простым решением. Но альтернативой может быть создание доступного для записи каталога в файловой системе, в которой имеется некоторое свободное пространство, установка переменной средыTMPDIR
для указания на этот каталог и последующее выполнениеed
. (Раскрытие: я не уверен, будет ли это работать, но это не повредит.)Как только вы начнете
ed
работать, вы можете автоматизировать это, выполнивв сценарии. Или , как предложено don_crissti.
printf '%s\n' 'g/myregex/d' w q | ed -s filename
источник
ed
или сex
), чтобы использовать память, а не отдельную файловую систему? Это то, к чему я действительно стремился (и причина, по которой я не принял ответ.)ed
много лет назад. Были еще такие вещи, как 16-разрядные компьютеры, на которых процессы были ограничены адресным пространством размером 64 КБ (!), Поэтому идея редактора, считывающего весь файл в память, была неискусной. С тех пор, конечно, объем памяти увеличился - но и диски, и файлы тоже. Поскольку диски такие большие, люди не чувствуют необходимости иметь дело с нехваткой/tmp
места. Я просто быстро взглянул на исходный код недавней версииed
, и он все еще кажется… (продолжение)ed
(илиex
илиvi
) предлагает возможность сохранить буфер в памяти. С другой стороны, Редактирование текста с помощью ed и vi - Глава 11: Обработка текста - Часть II: Изучение Red Hat Linux - Профессиональные секреты Red Hat Linux 9 - Системы Linux говорят, чтоed
буфер редактирования находится в памяти,… (Продолжение )vi
( о том же, что и программаex
). Я считаю, что они просто используют неаккуратную, неточную формулировку - но, если она есть в Интернете (или в печати), это должно быть правдой, верно? Вы платите свои деньги и делаете выбор.Вы можете довольно легко обрезать файл, если вы можете получить количество байтов до смещения, и ваши строки происходят от начальной точки до конца.
Или, если вы
${TMPDIR:-/tmp}
находитесь в другой файловой системе, возможно:Потому что (большинство) оболочки помещают свои документы здесь в удаленный временный файл. Это совершенно безопасно, если
<<FILE
дескриптор поддерживается от начала до конца и${TMPDIR:-/tmp}
имеет столько места, сколько вам нужно.Оболочки, которые не используют временные файлы, используют каналы, и поэтому их использование небезопасно. Эти оболочки , как правило ,
ash
производные , такие какbusybox
,dash
, BSDsh
-zsh
,bash
,ksh
, и Bourne оболочки, однако, все использовать временные файлы.по-видимому, я написал небольшую программу оболочки в июле прошлого года, чтобы сделать что-то вроде этого
Если
/tmp
это не жизнеспособно, то пока вы можете поместить файл в память что-то вроде ...... в общем случае, по крайней мере, убедитесь, что файл был полностью буферизован первым
sed
процессом, прежде чем пытаться усечь файл ввода / вывода.Более целенаправленным и эффективным решением может быть:
... потому что это не будет беспокоить буферизацию строк, которые вы хотели удалить в любом случае.
Тест общего случая:
источник
/tmp
которые находятся в одной файловой системе. Мне нравится ваша двойнаяsed
версия. Я думаю, что комбинация ответа Бармара и вашего ответа, вероятно, была бы лучшей, что-то вроде:myvar="$(sed '/myregex/d' < file)" && [ -n "$myvar" ] && echo "$myvar" > file ; unset myvar
(Для этого случая меня не волнует сохранение завершающих строк.)sed
|cat
вещь выше никогда не открывает вывод, еслиsed
он уже не буферизовал весь файл и не готов начать запись всего этого для вывода. Если он пытается буфер файл и не -read
не увенчались успехом , поскольку находки EOF на|
трубе , прежде чем он читает свой первый символ новой строки и такcat >out
никогда не бывает до своего времени , чтобы записать его из памяти целиком. переполнение или что-то подобное просто терпит неудачу. также весь конвейер каждый раз возвращает успех или неудачу. хранить его в переменной просто более рискованно.file=$(sed '/regex/!H;$!d;x' <file | read v && tee file) && cmp - file <<<"$file" || shite
поэтому выходной файл и переменная будут записываться одновременно, что создаст одно или эффективное резервное копирование, и это единственная причина, по которой вы хотите усложнять вещи дальше, чем нужно.read script
иread v
в вашем ответе. Если вы можете подробнее рассказать об этом, я буду очень признателен, спасибо!$script
этоsed
скрипт, который вы бы использовали для нацеливания на любую часть вашего файла, которую вы хотели; это скрипт, который дает вам конечный результат, который вы хотите в потоке.v
это просто заполнитель для пустой строки. вbash
оболочке это не является необходимым, поскольку вместо негоbash
будет автоматически использоваться$REPLY
переменная оболочки, если вы ее не указали, но POSIXly всегда следует делать так. я рад, что вы нашли это полезным, кстати. удачи с этим. Я mikeserv @ Gmail, если вам нужно что-нибудь в глубине. через несколько дней у меня должен снова быть компьютерЭтот ответ заимствует идеи из этого другого ответа и этого другого ответа, но основывается на них, создавая ответ, который более применим:
Первая строка запускает
sed
команду с выводом, записанным в стандартный вывод (а не в файл); в частности, на трубу,wc
чтобы считать персонажей. Во второй строке также выполняетсяsed
команда с выводом, записанным в стандартный вывод, который в этом случае перенаправляется во входной файл в режиме чтения / записи с перезаписью (без усечения), который обсуждается здесь . Это довольно опасная вещь; это безопасно только тогда, когда команда фильтра никогда не увеличивает объем данных (текст); то есть для каждого n байтов, которые он читает, он пишет n или меньше байтов. Это, конечно, верно дляsed '/myregex/d'
команды; для каждой строки, которую он читает, он пишет ту же самую строку, или ничего. (Другие примеры:s/foo/fu/
илиs/foo/bar/
было бы безопасно, ноs/fu/foo/
иs/foo/foobar/
не будет.)Например:
потому что эти 32 байта данных:
был перезаписан этими 25 символами:
оставив семь байтов,
night.\n
оставшихся в конце.Наконец,
dd
команда ищет до конца новые очищенные данные (байт 25 в этом примере) и удаляет остальную часть файла; то есть, он усекает файл в этой точке.Если по какой-либо причине
1<>
трюк не работает, вы можете сделатьКроме того, обратите внимание, что, пока все, что вы делаете, это удаление строк, все, что вам нужно - это
grep -v myregex
(как указал Barmar ).источник
sed -i 'd' / путь / к / файлу / имени файла
источник