Я пишу сценарии оболочки для моего сервера, который является общим хостингом под управлением FreeBSD. Я также хочу иметь возможность тестировать их локально, на моем компьютере под управлением Linux. Следовательно, я пытаюсь написать их портативным способом, но sed
я не вижу способа сделать это.
Часть моего сайта использует сгенерированные статические HTML-файлы, и эта строка sed вставляет правильный DOCTYPE после каждой регенерации:
sed -i '1s/^/<!DOCTYPE html> \n/' ${file_name.html}
Он работает с GNU sed
в Linux, но FreeBSD sed
ожидает, что первым аргументом после -i
опции будет расширение для резервной копии. Вот как это будет выглядеть:
sed -i '' '1s/^/<!DOCTYPE html> \n/' ${file_name.html}
Однако GNU, sed
в свою очередь, ожидает, что выражение последует сразу после -i
. (Это также требует исправлений с обработкой новой строки, но здесь уже есть ответ )
Конечно, я могу включить это изменение в свою серверную копию скрипта, но это может испортить то, что я использую VCS для управления версиями. Есть ли способ добиться этого с помощью Sed в полностью портативном виде?
-i
Ответы:
GNU sed принимает необязательное расширение после
-i
. Расширение должно быть в том же аргументе без пробела. Этот синтаксис также работает на BSD sed.Обратите внимание, что в BSD
-i
также изменяется поведение при наличии нескольких входных файлов: они обрабатываются независимо (например,$
соответствуют последней строке каждого файла). Также это не будет работать на BusyBox.Если вы не хотите использовать файлы резервных копий, вы можете проверить, какая версия sed доступна.
Или, в качестве альтернативы, чтобы избежать путаницы позиционных параметров, определите функцию.
Если вы не хотите беспокоиться, используйте Perl.
Если вы хотите написать переносимый скрипт, не используйте
-i
его - его нет в POSIX. Делайте вручную то, что sed делает под капотом - это всего лишь еще одна строка кода.источник
sed -i
также подразумевает-s
. И самый простой способ проверить наличие GNUsed
- этоsed v
команда, которая является допустимым noop для GNU, но не работает везде.sed -i$(sed v < /dev/null 2> /dev/null || echo -n " ''") -e '...' "$file"
если это не GNU sed, она вставляет пробел, за которым следуют две одинарные кавычки,-i
так что работает на BSD. Достается только GNU sed-i
.v
команды для тестирования на GNU sed. Что если FreeBSD решит это реализовать?sed v
что это его цель для существования.Если вы не нашли способ сделать
sed
игру приятной, вы можете попробовать:Не используйте
-i
:Используйте Perl
источник
издание
Вы всегда можете использовать
ed
для добавления строки к существующему файлу.Детали
Биты вокруг
<!DOCTYPE html>
являются командами, которые дают емуed
команду добавить эту строку в файлmy.html
.СЭД
Я считаю, что эту команду
sed
также можно использовать:источник
Вы также можете сделать вручную, что
perl -i
делает под капотом:Например
perl -i
, нет резервной копии, и, как и большинство решений, приведенных здесь, имейте в виду, что это может повлиять на разрешения, владение файлом и превратить символическую ссылку в обычный файл.С:
sed
перезаписывает файл поверх самого себя, поэтому не влияет на владение и разрешения или символические ссылки. Он работает с GNU,sed
потомуsed
что обычно будет читать буфер, полный данныхfile
(в моем случае 4k), перед тем как перезаписать егоi
командой. Это не сработало бы, если бы файл был больше 4k, за исключением того факта, что онsed
также буферизировал его вывод.В основном
sed
работает на блоках по 4к для чтения и записи. Если строка для вставки меньше, чем 4 КБ,sed
никогда не будет перезаписывать блок, который он еще не прочитал.Я бы на это не рассчитывал.
источник
echo '<!DOCTYPE html>'
или экранированы без "" кавычек.Для FreeBSD sed , которая также используется в Mac OS X,
-e
после параметра требуется опция,-i
позволяющая правильно и однозначно определить и распознать следующую (regex) команду.Другими словами,
sed -i -e ...
должен работать как с FreeBSD, так и с GNUsed
.В более общем смысле, исключение расширения резервной копии после FreeBSD
sed -i
требует некоторого явногоsed
параметра или переключателя, следующих за тем,-i
чтобы избежать путаницы в части FreeBSDsed
при анализе аргументов командной строки.(Однако обратите внимание, что
sed
редактирование файлов на месте приводит к изменениям inode файла, см. «Редактирование файлов на месте» ).(Как общий совет, последние версии FreeBSD
sed
имеют-r
переключатель для повышения совместимости с GNUsed
).источник
bsdsed -i -e 's/a/A/'
это не редактирование на месте, это редактирование с сохранением оригинала с суффиксом "-e" (testfile.txt-e
).Чтобы эмулировать
sed -i
один файл для переноса, максимально избегая условий гонки:Кстати, это также решает возможную проблему, которая возникает
sed -i
в том, что, в зависимости от прав доступа к каталогу и файлу,sed -i
может позволить пользователю перезаписать файл, для которого у этого пользователя нет прав на редактирование.Вы могли бы также сделать резервные копии как:
источник
Вы можете использовать Vim в режиме Ex:
1
выберите первую строкуi
вставить текст и перевод строкиx
сохранить и закрытьИли даже, как в комментариях, простой старый стандарт
ex
:источник
ex
исключением того, что реализации не требуют поддержки нескольких-c
флагов. Для определенной переносимости я бы использовалprintf '%s\n' 1i '<!DOCTYPE html>' . x | ex file