给出以下命令:
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 。出于其他原因不使用。
它在perlrun中说
请注意,由于
-i在创建具有相同名称的新文件之前重命名或删除了原始文件,因此将不保留Unix样式的软链接和硬链接。
因此,不能使用来做到这一点-i。
这是Perl的另一种方式(如标记所示-即使有干净的解决方案sed)
我使用文件a.txt,b.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适当地进行设置,因为该模块已被使用。
使用的eof检查每个输入文件的文件是否用尽,这时将输出文件重命名为输入文件或其目标。该-l是一个文件测试操作该测试是否手边的文件是一个符号链接,如果是那么的readlink解析链接。
rename因为此时已读取并处理了输入文件或目标,所以它是安全的。
在$ ARGV为当前处理文件的名称和ARGV是它的文件句柄。
显式close ARGV重置行计数器,因此我们可以通过测试行号计数器$在每个新输入文件的开头打开临时输出。反对1。