Как я могу достигнуть мобильности с sed-i (оперативное редактирование)?

Что-то как egrep "^https?:\/\/" yourlistofurls или Вы хотите проверить, что тот URL указывает на допустимое http содержание, также?

45
03.04.2019, 23:41
7 ответов

GNU sed принимает дополнительное расширение после -i. Расширение должно быть в том же аргументе без прошедшего пространства. Этот синтаксис также работает над BSD sed.

sed -i.bak -e '…' SOMEFILE

Отметьте это на BSD, -i также изменяет поведение, когда существует несколько входных файлов: они обрабатываются независимо (так, например. $ соответствует последней строке каждого файла). Также это не будет работать над BusyBox.

Если Вы не хотите использовать файлы резервных копий, Вы могли бы проверить, какая версия sed доступна.

case $(sed --help 2>&1) in
  *GNU*) set sed -i;;
  *) set sed -i '';;
esac
"$@" -e '…' "$file"

Или альтернативно, чтобы не ударять позиционные параметры, определяют функцию.

case $(sed --help 2>&1) in
  *GNU*) sed_i () { sed -i "$@"; };;
  *) sed_i () { sed -i '' "$@"; };;
esac
sed_i -e '…' "$file"

Если Вы не хотите беспокоиться, используйте Perl.

perl -i -pe '…' "$file"

Если Вы хотите записать портативный сценарий, не использовать -i — это не находится в POSIX. Сделайте вручную, что sed делает под капотом — это - только еще одна строка кода.

sed -e '…' "$file" >"$file.new"
mv -- "$file.new" "$file"
44
27.01.2020, 19:34
  • 1
    GNU sed -i также подразумевает -s. И самый легкий способ проверить на GNU sed с sed v команда, которая еще является допустимым noop для GNU, но сбоев везде. –  mikeserv 04.09.2014, 22:11
  • 2
    , Вдохновленное вышеупомянутыми подсказками, вот одна строка (если ужасна) портативная версия для тех, кто действительно хочет один, хотя это действительно порождает подоболочку: sed -i$(sed v < /dev/null 2> /dev/null || echo -n " ''") -e '...' "$file" Если это не GNU sed, это вставляет пробел, сопровождаемый двумя кавычками ожога после -i так, чтобы это работало над BSD. GNU sed добирается только -i. –  Ivan X 27.04.2015, 00:42
  • 3
    @IvanX я опасаюсь использовать присутствие v управляйте для тестирования на GNU sed. Что, если FreeBSD решил реализовать его? –  Gilles 'SO- stop being evil' 27.04.2015, 00:54
  • 4
    @Gilles, но страница справочника для GNU sed описывает v, как являющийся точно с этой целью (обнаруживающий, что это - GNU sed и не что-то еще), таким образом, можно было бы надеяться, что *BSD будет соблюдать это. Я не могу думать о другом тесте, бесцеремонно, который не принимает мер по GNU sed, при порождении ошибки на BSD sed (или наоборот), кроме использования-i самого, но это потребовало бы создания фиктивного файла сначала. Ваш тест для sed выше в порядке, но является громоздким для встроенного. Предотвращение-i полностью, как Вы предполагаете, конечно, походит на самую безопасную ставку, но я соглашаюсь с использованием sed v учитывая это - его цель для существующего. –  Ivan X 27.04.2015, 01:20
  • 5
    @lapo альтернатива должна определить функцию, видят мое редактирование. –  Gilles 'SO- stop being evil' 22.03.2016, 14:04

Если Вы не находите, что прием делает sed играйте по правилам, Вы могли попробовать:

  1. Не использовать -i :

    sed '1s/^/<!DOCTYPE html> \n/' "${file_name.html}" > "${file_name.html}.tmp" &&
      mv "${file_name.html}.tmp" "${file_name.html}"
    
  2. Используйте Perl

    perl -i -pe 'print "<!DOCTYPE html> \n" if $.==1;' "${file_name.html}"
    
10
27.01.2020, 19:34

редактор

Можно всегда использовать ed предварительно ожидать строку в существующий файл.

$ printf '0a\n<!DOCTYPE html>\n.\nw\n' | ed my.html

Подробнее

Биты вокруг <!DOCTYPE html> команды к ed инструктирование этому добавить, что строка к файлу my.html.

sed

Я верю этой команде в sed может также использоваться:

$ sed -i '1i<!DOCTYPE html>\n` testfile.csv
8
27.01.2020, 19:34
  • 1
    я в конечном счете обратился к Perl, но редактор использования является хорошей альтернативой, это не популярно среди подобных Unix пользователей, как это должно быть. –  Red 30.09.2013, 17:29
  • 2
    @Red - довольный услышать Вы разрешили, что выходите. Да я не видел, что один прежде, гугля поднял его, и это на самом деле походило на самый портативный, способный способ сделать это. –  slm♦ 30.09.2013, 17:30

Можно также сделать вручную что perl -i делает под капотом:

{ rm -f file && { echo '<!DOCTYPE html>'; cat; } > file;} < file

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

С:

sed '1i\
<!DOCTYPE html>' file 1<> file

sed перезаписал бы файл по себе, так не будет влиять на владение и полномочия или символьные ссылки. Это работает с GNU sed потому что sed будет обычно читать буфер, полный данных из file (4k в моем случае) прежде, чем перезаписать его с i команда. Это не работало бы, если бы файл был больше, чем 4k за исключением факта это sed также буферизует его вывод.

В основном sed работы над блоками 4k для чтения и записи. Если строка для вставки меньше, чем 4k, sed никогда не будет перезаписывать блок, который это еще не считало.

Я не рассчитывал бы на него все же.

7
27.01.2020, 19:34
  • 1
    Должен быть echo '<!DOCTYPE html>' или вышел без "" кавычек. –  A.D. 22.05.2015, 15:36
  • 2
    @A.D. Положительная сторона. Я склонен забывать о том bug^Wfeature интерактивного bash/zsh, поскольку я обычно отключаю его для меня. –  Stéphane Chazelas 22.05.2015, 15:41
  • 3
    Это - один из очень немногих ответов здесь, который не имеет широко открытой дыры в системе безопасности перенаправления во "временный файл" со статическим, предсказуемым именем, не проверяя, существует ли это уже. Я полагаю, что это должно быть принятым ответом. Очень хорошая демонстрация использования команд группы, также. –  Wildcard 11.03.2016, 03:59

Для FreeBSD sed, который используется на Mac OS X также, нужно -e опция после -i переключатель, чтобы определить и распознать следующий (regex) управляет правильно и однозначно.

Другими словами, sed -i -e ... должен работать с обеими FreeBSD & GNU sed.

В более общем плане, опуская резервное расширение после FreeBSD sed -i требует некоторых явных sed опция или переключатель после -i избегать беспорядка со стороны FreeBSD sed при парсинге его параметров командной строки.

(Отметьте, однако, это sed оперативный вывод редактирований файла в файл inode изменения, см. "Оперативное" редактирование файлов).

(Как общая подсказка, последние версии FreeBSD sed имейте -r переключитесь для увеличения совместимости с GNU sed).

echo a > testfile.txt
ls -li testfile.txt
#gsed -i -e 's/a/A/' testfile.txt
#bsdsed -i 's/a/A/' testfile.txt  # does not work
bsdsed -i -e 's/a/A/' testfile.txt
ls -li testfile.txt
cat testfile.txt
3
27.01.2020, 19:34
  • 1
    Нет, bsdsed -i -e 's/a/A/' не оперативное редактирование, оно редактирует с сохранением оригинала с суффиксом "-e" (testfile.txt-e). примечание –  Stéphane Chazelas 22.05.2015, 14:27
  • 2
    , что GNU sed также поддерживает-E (в дополнение к-r) для совместимости с FreeBSD.-E, вероятно, будет указан в следующей версии POSIX, таким образом, мы должны будем все забыть об этом-r ерунду и притворяться, что это никогда не существовало. –  Stéphane Chazelas 22.05.2015, 14:30

Эмулировать sed -i для одного файла портно, избегая при этом гоночных условий, насколько это возможно:

sed 'script' <<FILE >file
$(cat file)
FILE

Кстати, это также решает возможную проблему, которую вводит sed -i, что в зависимости от прав доступа к каталогу и файлу, sed -i может позволить пользователю перезаписать файл, на редактирование которого у этого пользователя нет прав.

Вы также можете делать резервное копирование, например:

sed 'script' <<FILE >file
$(tee file.old <file)
FILE
2
27.01.2020, 19:34

Вы можете использовать Vim в режиме Ex:

ex -sc '1i|<!DOCTYPE html>' -cx file
  1. 1 выбрать первую строку

  2. i вставить текст и новую строку

  3. x сохранить и закрыть

Или даже, как в комментарии, старый добрый стандартный пример :

printf '%s\n' 1i '<!DOCTYPE html>' . x | ex file 
2
27.01.2020, 19:34

Теги

Похожие вопросы