Есть ли альтернатива команде «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 будет убит до его завершения.

  • Как проверить, какая версия редактора VI у меня есть?
  • Как удалить устройство из пула
  • Как использовать «фьюзер» для получения списка процессов для вложенной папки при использовании с родительской папкой в ​​качестве аргумента?
  • Наследование прав на запись группы, но не выполнение для файлов, на OmniOS (Illumos) с использованием ZFS ACL
  • Mailx заменить из: адрес с именем
  • Solaris 10, команда useradd
  • В Solaris 10 и 11 все еще используется распределение slab для их распределителя памяти ядра
  • Как завершить графический интерфейс в SunOS из shell-script
  • ssh туннелирование локального экрана на другой сервер
  • Пределы дескриптора файла в / etc / system vs /etc/sysctl.conf vs /etc/security/limits.conf в Solaris
  • Как распечатать строку, если эта строка или следующая строка не содержат определенную строку
  • Interesting Posts

    DHCP работает по Wi-Fi, но мой компьютер не может принимать одноадресные пакеты только широковещательные пакеты

    Сценарий, который использует запрос MySQL для автоматического удаления вывода

    ` <defunct>` с несуществующими детьми -> Любой способ их сбора?

    Не удается удалить расширение Gnome Shell

    GNOME распознает второй монитор, когда он подключен. Не работает ли Openbox?

    Исходный код ядра Linux, разность размеров

    Закладка autocomplete для файлов с пробелами в нем

    Синтаксис Grep Perl и авторский характер

    fstrim "операция сброса не поддерживается" с ext4 на LVM

    Default-Start не содержит уровней запуска

    Как я могу изменить действие по умолчанию на экране Ca на просто обратную сторону `?

    Как отобразить устройство «Имя» при запуске hcitool lescan и btmon?

    Rsync для копирования определенных подпапок и файлов в новый каталог

    Понимание / etc / aliases и что он делает

    Использование стрелки вверх для получения предыдущей команды в netcat

    Linux и Unix - лучшая ОС в мире.