代码之家  ›  专栏  ›  技术社区  ›  zzxyz

使用perl将已更改的软链接/symlink替换为静态文件

  •  3
  • zzxyz  · 技术社区  · 6 年前

    发出以下命令:

    git ls-files | xargs perl -i -pe 's/SEARCHTERM/REPLACETERM/g'
    

    所有到perl的输出(从gitls文件)都是符号链接,现在 副本

    我有两个问题:

    2) 在本地git分支上执行搜索和替换有更好的通用方法吗?

    可能值得注意的是,我的bash是相当初级的 xargs 处理的是文件列表,而不是文件列表。除此之外,不得用于任何其他原因。

    5 回复  |  直到 6 年前
        1
  •  2
  •   Rafael    6 年前

    git ls-files | xargs -I{} -P4 sed --follow-symlinks -i'' 's/SEARCHTERM/REPLACETERM/g' {} 
    
        2
  •  5
  •   zdim    6 年前

    上面写着 perlrun

    请注意,因为 -i

    所以我们不能这样做 -我

    这是另一种使用Perl的方法(如标签所示——尽管有一个使用Perl的干净解决方案) sed )

    a.txt b.txt ,它们的符号链接( ln -s a.txt ln_a.txt c.txt (任何内容都可以测试),并列出链接和 在文件中

    ln_a.txt ln_b.txt c.txt    # file "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) }
    '
    

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

    filename_tmp.$$ File::Temp ,或者更确切地说 Path::Tiny::tempfile 因为那个模块已经在使用了。

    这个 rename move File::Copy ,便于携带。

    eof as used检查每个输入文件的文件是否已用尽,此时输出文件将重命名为输入文件或其目标。这个 -l 是一个 file-test operator 这将测试手头上的文件是否是符号链接,以及是否是符号链接 readlink 解析链接。

    rename 输入文件或目标,因为它已经被读取和处理。

    这个 $ARGV 名字是什么 ARGV 是它的文件句柄。

    明确的 close ARGV $. 反对 1 .

        3
  •  2
  •   Grinnz    6 年前

    另一个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目标,并且 edit_lines 本质上是 -i 选项。使用 edit_lines_utf8 -Mutf8 意味着您的源代码(搜索和替换术语)和文件内容将在运行搜索/替换时从UTF-8解码,这通常很有用(但如果您的文件不是UTF-8编码的,请删除) 使用 edit_lines ). 您还可以根据 -T heuristic 通过添加 grep { -T } for

    作为奖励, 编辑\u行 将总是输出到一个新文件,然后将其重命名为原始文件,这比重击原始文件更安全,因为 -i didn't do until Perl 5.28 .

    注意:Path::Tiny将根据当前umask设置它编辑的所有文件的权限,而不是现有权限;我打开了 an issue

        4
  •  2
  •   ikegami    6 年前

    你只需要

    git ls-files | xargs readlink -e | xargs perl -i -pe'...'
    

    您还可以在Perl中扩展链接。

    git ls-files | xargs perl -i -pe'BEGIN { @ARGV = map readlink($_) // $_, @ARGV } ...'
    
        5
  •  1
  •   zzxyz    6 年前

    我最初的解决方案是让符号链接受到重击,然后运行:

    git status --porcelain | awk '{if ($1 == "T"){print $2}}' | xargs git checkout
    

    如果符号链接碰巧是偶然的并且与搜索无关,那么这些工具可能会破坏它们。

    这里的链接有一些有趣的想法: https://unix.stackexchange.com/questions/9318/is-there-a-way-to-make-perl-i-not-clobber-symlinks

    sponge ,可以工作,但会创建非常复杂的xargs管道。我认为这也需要使用 xargs -n1 ,这是一个 在大型文件系统上运行perl的慢方法。所以那是不可能的。

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