Sed с редактированием на месте меняет группу владельцев файла

8

У меня есть phpскрипт shell ( ), который связывается с целевым файлом следующим образом:

  • проверяет, можно ли записать файл и каталог с помощью phps is_writable()(я не думаю, что это проблема)
  • выполняет редактирование файла на месте с помощью sedкоманды:

grep -q "$search" "$passwd_file" && { sed -i "s|$search|$replace|" "$passwd_file"; printf "Password changed!\n"; } || printf "Password not changed!\n"

В результате я получаю (все остальное правильно, но) файл, который должен myuser:www-dataбыл быть myuser:myuser.

Изменяет ли sedвладение файловую группу, как кажется, и как мне избежать этого, если это возможно?

Милош Чаконович
источник

Ответы:

16

Существует небольшая проблема с sedрежимом редактирования на месте -i. sedсоздает временный файл в том же каталоге sedy08qMA, где и y08qMAнаходится случайно сгенерированная строка. Этот файл заполнен измененным содержимым исходного файла. После операции sedудаляет исходный файл и переименовывает временный файл с исходным именем файла. Так что это не настоящее редактирование на месте . Он создает новый файл с разрешениями вызывающего пользователя и новым номером инода. Такое поведение в основном неплохое, но, например, жесткие ссылки нарушаются.

Однако, если вы хотите истинное редактирование на месте, вы должны использовать ed. Он читает команды из стандартного ввода и редактирует файл напрямую, без временного файла (это делается через edбуфер памяти). Обычной практикой является использование printfдля генерации списка команд:

printf "%s\n" '1,$s/search/replace/g' wq | ed -s file

Команда printfпроизводит вывод следующим образом:

1,$s/search/replace/g
wq

Эти две строки являются edкомандами. Первый ищет строку searchи заменяет ее на replace. Второй пишет ( w) изменения в файле и выходит ( q). -sподавляет диагностический вывод.

хаос
источник
8

-iПараметр sedработ пути создания временного файла во время работы, а затем перезаписать сам файл с временным файлом в конце. Это наиболее вероятная причина проблемы, так как при создании временного файла владельца по умолчаниюmyuser:myuser

Вы можете установить setgidбит в родительском каталоге (только если родительский каталог принадлежит группе www-data), чтобы файлы, созданные в этом каталоге, наследовали одну и ту же группу.
сделать это:

chmod g+s parent-dir-of-your-file  

Я думаю, что это очень типичное использование setgidбита.

Dave.d
источник
@cuonglm Я только что выпрямился sed -i, нашел следующую строку в трассировке, означает ли это, что он создал временный файл в текущем каталоге? open("./sedKyG9Ei", O_RDWR|O_CREAT|O_EXCL, 0600) = 4
Dave.d
@DavidDai: Да, моя ошибка.
cuonglm
2

Использование edвместо вместо этого sedкажется довольно излишним, учитывая, что вам нужно добавить дополнительный ввод. В дистрибутиве, над которым я сейчас работаю (CentOS 5.10), есть -cопция, sedкоторая использует «копирование» временного файла, а не просто переименовывает его при использовании с этой -iопцией. Я протестировал его, и он отлично работал, сохранив первоначального владельца и группу при выполнении встроенного редактирования. Это НЕ сохраняет время модификации.

например, sed -ci -e '3,5d' file.txt

  • -c использует копию вместо переименования (то есть сохраняет собственность / группу)
  • -i встроенное редактирование
  • -e скрипт / выражение для выполнения

Не уверен, насколько распространен этот параметр для sedдругих дистрибутивов. У Solaris 10 его не было, но у Solaris не так много вещей, которые я хочу.

devnulldad
источник
Звучит довольно удобно. Не в Ubuntu 14.04, хотя, FWIW. :-(
Джон Рикс