使用perl到位替换已更改的静态链接/符号链接到静态文件

zzx*_*xyz 3 git bash perl

给出以下命令:

git ls-files | xargs perl -i -pe 's/SEARCHTERM/REPLACETERM/g'
Run Code Online (Sandbox Code Playgroud)

现在,作为符号链接的所有perl输出(来自git ls文件)都是目标文件的副本

我有两个问题:

1)我想我隐约理解为什么会这样,但只是隐约。有人可以详细解释吗?并提出避免这种情况的最佳机制?预期的行为是符号链接目标将成为读取和写入的目标,而不仅仅是读取。

2)是否有更好的通用方法可以在本地git分支上进行搜索和替换?

可能值得一提的是,xargs当我要确保处理文件的内容而不是文件列表时,我的bash非常基本,只是我的默认goto 。出于其他原因不使用。

zdi*_*dim 5

它在perlrun中

请注意,由于-i在创建具有相同名称的新文件之前重命名或删除了原始文件,因此将不保留Unix样式的软链接和硬链接。

因此,不能使用来做到这一点-i

这是Perl的另一种方式(如标记所示-即使有干净的解决方案sed

我使用文件a.txtb.txt它们的符号链接(ln -s a.txt ln_a.txt等)和c.txt(并且任何内容都适合该测试),并c.txt在文件中列出链接的名称

ln_a.txt ln_b.txt c.txt#文件“ input_list.txt”

其中的文件/链接名称input_list.txt可以用空格或换行符分隔。

然后,在每个输入文件的第一行中打开一个临时输出文件,并将每个处理过的行写入其中。一旦到达输入文件的末尾,则将该临时输出重命名为其输入文件,如果是链接,则重命名为其目标。因此,对于每个输入文件,请使用输出文件覆盖该文件或目标(如果链接)。

cat input_list.txt | xargs perl -MPath::Tiny -ne'
    if ($.==1) { $tf = $ARGV."_tmp.$$"; $fh = path($tf)->openw };
    s/(\w+)/$1-NEW/; 
    print $fh $_; 
    if (eof) { close ARGV; rename $tf, (-l $ARGV ? readlink $ARGV : $ARGV) }
'
Run Code Online (Sandbox Code Playgroud)

这将更改目标的内容,并仅保留链接。它也适用于常规文件。

临时输出文件名(filename_tmp.$$)可以使用File::Temp或使用Path :: Tiny :: tempfile适当地进行设置,因为该模块已被使用。

重命名也许应该改为move文件::复制,便于携带。

使用的eof检查每个输入文件的文件是否用尽,这时将输出文件重命名为输入文件或其目标。该-l是一个文件测试操作该测试是否手边的文件是一个符号链接,如果是那么的readlink解析链接。

rename因为此时已读取并处理了输入文件或目标,所以它是安全的。

$ ARGV为当前处理文件的名称和ARGV是它的文件句柄。

显式close ARGV重置行计数器,因此我们可以通过测试行号计数器$在每个新输入文件的开头打开临时输出反对1