有没有办法使perl -i不破坏符号链接?


12

我的一个朋友指出,如果您这样做:

perl -pi.bak -e 's/foo/bar/' somefile

当“ somefile”实际上是一个符号链接时,perl会按照文档所说的去做:

它通过重命名输入文件,使用原始名称打开输出文件并选择该输出文件作为print()语句的默认值来做到这一点。该扩展名(如果提供)用于修改旧文件的名称以制作备份副本[...]

这将导致指向未更改的实际文件的新符号链接“ somefile.bak”,以及具有更改的新的已更改常规文件“ somefile”。

在许多情况下,遵循符号链接将是理想的行为(即使它使.bak文件的正确位置不明确)。除了测试包装器中的符号链接并适当处理大小写以外,还有其他简单的方法吗?

sed做同样的事情,这是值得的。)


1
调用vim或emacs(我认为两者都遵循符号链接)?认真地说,我担心答案是-p -i在脚本中重新实现。
吉尔(Gilles)“所以,别再邪恶了”,

Sed实际上并没有做同样的事情,至少自2009年6月发布的4.2.1版本以来没有。 ; 我认为这样做是为了避免损坏可能依赖于旧行为的现有脚本。
Garrett 2014年

Answers:


6

我想知道sponge来自moreutils的小型通用实用程序(“吸收标准输入并写入文件”)在这种情况下是否会有所帮助,以及它是否会遵循符号链接。

作者描述 sponge如下:

它解决了使用Unix工具就地编辑文件的问题,即,如果您只是将输出重定向到您要编辑的文件,则重定向在管道中的第一个命令之前生效(使文件的内容杂乱无章)可以读取文件。这样的开关sed -iperl -i可以解决此问题,但并非您可能希望在管道中使用的每个命令都具有这样的选项,因此您始终不能将这种方法与多命令管道一起使用。

我通常这样使用海绵:

sed '...' file | grep '...' | sponge file

嘿,酷,可以。我怀疑上面的评论是Gilles的“真实”答案,但是由于他没有将其作为答案,并且由于我学习了一个新实用程序,因此我将使用它。:)
mattdm 2011年

但是您是否sponge在实践中测试过这种用法?至于我:还没有。您能否发表评论,说明它在测试中的行为是否符合此处的要求?哦,我看到了评论。感谢您的确认!
imz –伊万·扎哈拉里舍夫(Ivan Zakharyaschev)2011年

—是的,我在回复之前尝试过。当file在你上面的例子是一个符号链接,该链接被单独留下与真实文件改变。
mattdm 2011年

@mattdm:是的,谢谢您的确认!(我注意到您的话“有效”比我发表评论要
晚一点

3

如果您知道作为somefile符号链接的事实,则可以使用以下内容显式提供file的完整路径:

perl -pi.bak -e 's/foo/bar/' $(readlink somefile)

这样,原始符号链接将保持不变,因为现在直接使用原始文件进行替换。


但是的输出readlink可能仍然是另一个符号链接。最好的办法是使用-f或者-e(如果可用)zsh$file:P(:P)glob的预选赛如图@ikegami得到一个无符号链接路径。
斯特凡Chazelas

3

如果要处理的是单个文件,该命令将如下所示:

perl -i -pe'...' -- "$qfn"

然后,解决方案如下:

perl -i -pe'...' -- "$( readlink -e -- "$qfn" )"

这同时处理符号链接和非符号链接。


如果要处理大量文件,该命令将如下所示:

... | xargs -r perl -i -pe'...' --

然后,解决方案如下:

... | xargs -r readlink -ze -- | xargs -r0 perl -i -pe'...' --

这同时处理符号链接和非符号链接。


警告 readlink不是标准命令,因此它的存在,其参数和功能因系统而异,因此请务必检查您的文档。例如,某些实现具有-f(您也可以在此处使用),但没有-e,有些都不具有。busyboxreadlink -f行为类似于GNU readlink -e。并且某些系统具有realpath命令,而不是通readlink常表现为GNU 的命令readlink -f

请注意,使用GNU时readlink -e,无法解析为现有文件的符号链接会被静默删除。


@StéphaneChazelas,$var:P对我不起作用。(X='tmp' zsh -c 'perl -E"say for @ARGV" $X:P'输出tmp:P
ikegami

您需要使用zsh 5.3(2016)或更高版本$var:P。对于较旧的版本,您可以随时使用$var:A。有关差异的信息,请参见手册;对于引入的理由(实际界面),请参见zsh.org/mla/users/2016/msg00593.html:Prealpath()
斯特凡Chazelas

:A在4.3.10(2009)中添加,readlink -z2012年在GNU 中添加,我不知道其他readlink支持的实现-z)。请注意,使用GNU时xargs,通常需要该-r选项,除非可以保证输入不会为空。在这里,没什么大不了的(除非perl代码中包含BEGIN/ END语句),-i used with no filenames on the command line, reading from STDIN.如果发生这种情况,您只会得到警告。
斯特凡Chazelas

糟糕,我误读了-r的文档。我以为我做了相反的事情。已读。
ikegami
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.