Есть ли альтернатива команде «sed -i» в Solaris?

У меня есть требование в моем проекте заменить какой-то существующий текст в файле, например foo с другим текстом, например fooofoo :

 abc.txt name foo foo1 

Поэтому я попробовал:

 sed -i "s/foo/fooofoo/g" abc.txt 

Однако я получаю эту ошибку:

sed: незаконный вариант – i

Я нашел в руководстве, что я должен использовать:

 sed -i\ "s/foo/fooofoo/g" abc.txt 

Однако это тоже не работает.

Я нашел альтернативы в perl и awk но решение в Solaris sed было бы высоко оценено.

Я использую эту версию bash:

GNU bash, версия 3.2.57 (1) -release (sparc-sun-solaris2.10)

5 Solutions collect form web for “Есть ли альтернатива команде «sed -i» в Solaris?”

Используйте ed . Он доступен на большинстве платформ, и он может редактировать ваши файлы на месте.
Поскольку sed основан на ed синтаксис для замены шаблонов аналогичен:

 ed -s infile <<\IN ,s/old/new/g w q IN 

Если вы не можете установить GNU sed, используйте:

 sed "s/foo/fooofoo/g" abc.txt >abc.tmp && mv abc.tmp abc.txt 

Это использует перенаправление для отправки вывода sed во временный файл. Если sed успешно завершен, это перезаписывает abc.txt с временным файлом.

Как видно из исходного кода для GNU sed , это именно то, что делает sed -i . Таким образом, это примерно так же эффективно, как sed -i .

Если существует вероятность того, что abc.tmp уже существует, вы можете захотеть использовать mktemp или аналогичную утилиту для генерации уникального имени для временного.

Если вам нужен эквивалент sed -i.bak , это довольно просто.

Рассмотрим этот сценарий для GNU sed:

 #!/bin/sh # Create an input file to demonstrate trap 'rm -r "$dir"' EXIT dir=$(mktemp -d) grep -v '[[:upper:][:punct:]]' /usr/share/dict/words | head >"$dir/foo" # sed program - removes 'aardvark' and 'aardvarks' script='/aard/d' ########## # What we want to do sed -i.bak -e "$script" "$dir" ########## # Prove that it worked ls "$dir" cat "$dir/foo" 

Мы можем просто заменить отмеченную строку на

 cp "$dir/foo" "$dir/foo.bak" && sed -e "$script" "$dir/foo.bak" >"$dir/foo" 

Это перемещает существующий файл в резервную копию и записывает новый файл.

Если мы хотим получить эквивалент

 sed -i -e "$script" "$dir" # no backup 

то это немного сложнее. Мы можем открыть файл для чтения в качестве стандартного ввода, а затем отсоединить его, прежде чем направлять вывод sed для его замены:

 ( cp "$dir/foo" "$dir/foo.bak"; exec <"$dir/foo.bak"; rm "$dir/foo.bak"; exec sed -e "$script" >"$dir/foo" ) 

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

Обратите внимание, что мы стараемся сначала копировать, а не создавать новый файл foo – это важно, если файл известен более чем одним именем (т. Е. Имеет жесткие ссылки), и вы хотите быть уверены, что не нарушаете ссылки.

Во-первых, вы должны знать, что команда i\ вы говорите, предназначена для вставки строки текста – не для сохранения отредактированного текста в файл. Для использования sed для POSIX не существует.

Что вы можете сделать, это использовать ex , который указан POSIX :

 printf '%s\n' '%s/find/replace/g' 'x' | ex file.txt 

Команда x предназначена для «сохранения и выхода». Вы также можете использовать wq но x короче.

Знак % в начале подстановочной команды означает «Применить эту команду к каждой строке в буфере». Вы также можете использовать 1,$s/find/replace/g .


Одно существенное различие между ex и sed заключается в том, что sed является редактором потока . Он работает только последовательно, строчно. ex гораздо более гибкий, чем это, и на самом деле вы можете редактировать интерактивные текстовые файлы непосредственно в ex . Это непосредственный предшественник vi .

Использование sed и отсутствие видимого временного файла:

Вы можете избежать создания отдельного видимого «временного файла»:

 exec 3<abc.txt rm abc.txt sed 's/foo/fooofoo/' <&3 >abc.txt exec 3<&- 

объяснение

Unix-подобные системы фактически не удаляют содержимое файла с диска, пока он не будет отсоединен в файловой системе и не будет открыт ни в каком процессе. Таким образом, вы можете сделать exec 3< чтобы открыть файл в оболочке для чтения в дескрипторе файла 3, rm файл (который отделяет его от файловой системы), а затем вызвать sed с файловым дескриптором 3, используемым в качестве его ввода.

Обратите внимание, что это сильно отличается от этого:

 # Does not work. sed 's/foo/fooofoo/' <abc.txt >abc.txt 

Разница в том, что когда вы делаете это в одной команде, оболочка просто открывает тот же файл для чтения и для записи с возможностью обрезания файла – поскольку он все тот же файл, вы теряете содержимое. Но если вы откроете его для чтения, тогда rm его, затем откройте тот же путь для записи, вы на самом деле создаете новый файл с одним и тем же именем (но в новом месте на диске и на диске, так как оригинал все еще открыт): поэтому содержимое по-прежнему доступно.

Затем, как только вы закончите, вы можете закрыть ранее созданный дескриптор файла (это специальный синтаксис exec 3<&- ), который освобождает исходный файл, чтобы операционная система могла удалить (пометить как неиспользуемое) его дисковое пространство.

Предостережения

Есть несколько вещей, которые нужно помнить об этом решении :.

  1. Вы получаете только один «проход» через содержимое – нет никакого переносного способа для оболочки «искать» обратно в дескрипторе файла, поэтому, когда программа читает часть содержимого, другие программы будут видеть только оставшуюся часть файла. И sed прочитает весь файл.

  2. Есть небольшая вероятность того, что ваш исходный файл будет потерян, если ваш shell / script / sed будет убит до его завершения.

  • Почему результат grep зависит от пути к папке?
  • пусть rm обрезает файлы
  • Отключить нулевой пароль для пользователя root на машине Sunsolaris?
  • Solaris 11 nlsadm list-timezone issue
  • Nexenta (Solaris), странное членство пользователей в LDAP
  • Установка глобальных переменных среды при загрузке в Solaris 11
  • Как проверить, что «ls» выводит что-то ... с помощью одной команды?
  • Наследование прав на запись группы, но не выполнение для файлов, на OmniOS (Illumos) с использованием ZFS ACL
  • строки обработки текста столбцам для блока
  • Объем отправки zfs колеблется
  • Как я могу проверить или устранить неисправные аппаратные ссылки? "Mount: нет такого устройства"
  • Linux и Unix - лучшая ОС в мире.