我的一个朋友指出,如果你这样做:
perl -pi.bak -e 's/foo/bar/' somefile
当“somefile”实际上是一个符号链接时,perl 就会按照文档所说的那样执行:
它通过重命名输入文件、按原始名称打开输出文件并选择该输出文件作为 print() 语句的默认文件来实现此目的。扩展名(如果提供)用于修改旧文件的名称以制作备份副本 [...]
这会产生一个新的符号链接“somefile.bak”,指向未更改的真实文件,以及一个新的、已更改的常规文件“somefile”,其中包含更改。
在许多情况下,遵循符号链接将是所需的行为(即使它使 .bak 文件的正确位置不明确)。除了测试包装器中的符号链接并适当处理这种情况之外,是否有一种简单的方法可以做到这一点?
(sed
做同样的事情,为了它的价值。)
答案1
我想知道是否是小sponge
通用实用程序(“吸收标准输入并写入文件”)更多实用程序在这种情况下以及它是否遵循符号链接将会有所帮助。
作者描述 sponge
像这样:
它解决了使用 Unix 工具就地编辑文件的问题,即如果您只是将输出重定向到您要编辑的文件,则重定向会在管道中的第一个命令之前生效(破坏文件的内容)抽出时间来读取文件。诸如
sed -i
和 之类的开关可以perl -i
解决此问题,但并非您可能想要在管道中使用的每个命令都有这样的选项,并且无论如何您都不能在多命令管道中使用该方法。我通常使用海绵有点像这样:
sed '...' file | grep '...' | sponge file
答案2
如果您知道符号链接这一事实somefile
,则可以使用以下命令显式提供文件的完整路径:
perl -pi.bak -e 's/foo/bar/' $(readlink somefile)
这样,原始符号链接将保持不变,因为替换现在是直接使用原始文件完成的。
答案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
,有些则两者都没有。busybox
的readlink -f
行为类似于 GNU readlink -e
。有些系统有一个realpath
命令,而不是readlink
通常表现得像 GNU readlink -f
。
请注意,使用 GNU 时readlink -e
,无法解析为现有文件的符号链接将被静默删除。