Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash 使用perl将软链接/symlink更改为静态文件就地替换_Bash_Git_Perl - Fatal编程技术网

Bash 使用perl将软链接/symlink更改为静态文件就地替换

Bash 使用perl将软链接/symlink更改为静态文件就地替换,bash,git,perl,Bash,Git,Perl,发出以下命令: git ls-files | xargs perl -i -pe 's/SEARCHTERM/REPLACETERM/g' 所有输出到perl(来自git ls文件)的符号链接现在都是目标文件的副本 我有两个问题: 1) 我想我模糊地理解了为什么会发生这种事,但只是模糊地理解。有人能详细解释一下吗?并提出避免这种情况的最佳机制?预期的行为是,符号链接目标将是读和写的目标,而不仅仅是读 2) 在本地git分支上进行搜索和替换是否有更好的通用方法 可能值得注意的是,我的bash非常

发出以下命令:

git ls-files | xargs perl -i -pe 's/SEARCHTERM/REPLACETERM/g'
所有输出到perl(来自git ls文件)的符号链接现在都是目标文件的副本

我有两个问题:

1) 我想我模糊地理解了为什么会发生这种事,但只是模糊地理解。有人能详细解释一下吗?并提出避免这种情况的最佳机制?预期的行为是,符号链接目标将是读和写的目标,而不仅仅是读

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


可能值得注意的是,我的bash非常初级,当我希望确保处理文件内容而不是文件列表时,
xargs
只是我的默认goto。除此之外,不得使用。如果您不反对使用sed,请尝试一下:

git ls-files | xargs -I{} -P4 sed --follow-symlinks -i'' 's/SEARCHTERM/REPLACETERM/g' {} 
上面写着

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

因此,使用
-i
无法做到这一点

这里是Perl的另一种方法(正如标记的一样——即使有一个干净的解决方案使用
sed

我使用文件
a.txt
b.txt
、它们的符号链接(
ln-sa.txt ln_a.txt
等)和
c.txt
(任何内容都可以用于此测试),并在文件中列出链接和
c.txt
的名称

ln_a.txt ln_b.txt c.txt # file "input_list.txt" 这将更改目标的内容,并保留链接。它也适用于常规文件

临时输出文件名(
filename\u tmp.$
)可以使用
file::Temp
,或者更确切地说是使用,因为该模块已经被使用

为便于携带,可能应将更改为从移动到

as used检查每个输入文件的文件是否已用尽,此时输出文件将重命名为输入文件或其目标。
-l
是一个测试手头上的文件是否是符号链接的函数,如果是,则解析该链接

由于输入文件或目标已被读取和处理,因此此时可以安全地对其进行重命名

名字是什么 当前处理的文件的名称,并且是该文件的文件句柄


显式的
close ARGV
重置行计数器,这样我们就可以在每个新输入文件的开头打开临时输出,方法是根据
1

测试行号计数器。对此,我最初的解决方案是让符号链接被阻塞,然后运行:

git status --porcelain | awk '{if ($1 == "T"){print $2}}' | xargs git checkout
这对于各种工具来说非常有用,如果符号链接碰巧是偶然的,并且与搜索不相关,那么它们可能会破坏符号链接

这里的链接有一些有趣的想法:

我认为zdim的答案是其中一个的最佳实现。不过有点毛茸茸的

该链接的另一个答案是使用
海绵
,它可以工作,但会创建一个非常复杂的xargs管道。我认为,它还需要使用
xargs-n1
,这是在大型文件系统上运行perl的一种极其缓慢的方式。所以这是不可能的

Rafael的答案(仅使用sed)可能是……解决这个问题的最明智的方法:)

另一个Perl选项:

git ls-files | xargs perl -MPath::Tiny -Mutf8 -E'
  path($_)->realpath->edit_lines_utf8(sub { s/SEARCHTERM/REPLACETERM/g })
  for @ARGV'
或者不使用xargs,只需从STDIN读取文件名:

git ls-files | perl -MPath::Tiny -Mutf8 -E'
  path($_)->realpath->edit_lines_utf8(sub { s/SEARCHTERM/REPLACETERM/g })
  for map { chomp; $_ } readline'
realpath
确保您始终使用symlink目标,并且本质上是
-i
选项的一个Path::微小实现。使用
edit_lines\u utf8
-Mutf8
意味着您的源代码(搜索和替换术语)和文件内容将在运行搜索/替换时从UTF-8解码,这通常很有用(但如果您的文件不是UTF-8编码的,请删除
-Mutf8
并使用
编辑_lines
)。您还可以根据筛选出非文本文件,方法是在
for
之后添加
grep{-T}

作为奖励,
edit_line
将始终输出到新文件,然后将其重命名为原始文件,这比删除原始文件更安全

注意:Path::Tiny将根据您当前的umask设置其编辑的所有文件的权限,而不是现有权限;我打开查看它是否被认为是一个bug。

您只需要

git ls-files | xargs readlink -e | xargs perl -i -pe'...'
您还可以在Perl中扩展链接

git ls-files | xargs perl -i -pe'BEGIN { @ARGV = map readlink($_) // $_, @ARGV } ...'

恐怕是同样的结果。(虽然我不得不删除
fwiw)是的,这很有效。谢谢另外,“关注符号链接”是一个有用的谷歌搜索,它让我找到了这个:@zzxyz,这真是个漂亮的老板!Def将阅读更多关于moreutils的信息。谢谢。我希望我永远不必使用它,但如果我使用它,它将是无价的。@zzxyz是的,很好有
sed
功能和它的答案:)。这只是一个简单的
-i
实现,它尊重符号链接。它包含了一堆花絮,我希望这些花絮通常是有用的。
git ls-files | xargs perl -i -pe'BEGIN { @ARGV = map readlink($_) // $_, @ARGV } ...'