我有 shell ( php
) 脚本,它以这种方式与目标文件联系:
- 检查文件和目录是否可写
php
(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
会更改文件组所有权,如果可能的话,如何避免它?
答案1
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
抑制诊断输出。
答案2
-i
参数的工作原理是sed
在运行时创建一个临时文件,最后用该临时文件覆盖实际文件。这最有可能是问题的原因,因为创建临时文件所有权时默认为myuser:myuser
您可以setgid
在父目录上设置该位(仅当父目录属于 group 时www-data
),以便在此目录下创建的文件继承同一组。
要做到这一点:
chmod g+s parent-dir-of-your-file
我认为这是setgid
钻头的一个非常典型的用途。
答案3
考虑到您必须通过管道输入额外的输入,因此使用代替ed
似乎是多余的。sed
我现在正在开发的发行版(CentOS 5.10)具有利用临时文件“复制”的-c
选项sed
,而不是在与该-i
选项一起使用时简单地重命名它。我已经测试过它,它工作得很好,在进行内联编辑时保留了原始所有者和组。它不保留修改时间。
例如,sed -ci -e '3,5d' file.txt
-c
使用复制而不是重命名(即保留所有权/组)-i
行内编辑-e
要执行的脚本/表达式
不确定这个选项sed
在其他发行版中有多普遍。 Solaris 10没有,但是Solaris没有很多我想要的东西。
答案4
我努力了https://crates.io/crates/sd仅替换字符串即可正常工作。不修改标志。
要安装它,您需要安装 Rust,然后安装“cargo install sd”。
目前,在许多用例中,Rust 是 C/C++ 的可行替代语言,如下所示。您不会后悔安装它,以便时不时地获得更好的替代品。