【问题标题】:Change multiple hgrc files from default = http to default = ssh and default-pull = http将多个 hgrc 文件从 default = http 更改为 default = ssh 和 default-pull = http
【发布时间】:2018-04-06 08:27:22
【问题描述】:

我想更改多个 mercurial hgrc 文件。

起始文件(示例):

# example repository config (see "hg help config" for more info)
[paths]
default = http://ourmercurialserver.de/apps/

# path aliases to other clones of this repo in URLs or filesystem paths
...

想要的结果

# example repository config (see "hg help config" for more info)
[paths]
default = ssh://myusername@ourmercurialserver.de//path/to/repositories/apps/
default-push = http://ourmercurialserver.de/apps/

# path aliases to other clones of this repo in URLs or filesystem paths
...

我创建了几个命令。但是第一个在 Mac 上不起作用

  1. 插入第二行 default-push 并找到表达式 default = http(*):

    find . -type f -name 'hgrc' -exec sed -i '' s/((^)default = http(.*)($))/\1\n\default-push = \1/ {} +
    

    错误:-bash: 意外标记 `(' 附近的语法错误 (使用 (^) 和 ($) 和不使用时会发生错误)

  2. 将 default-push = default = http 替换为 default-push = http:

    find . -type f -name 'hgrc' -exec sed -i '' s/((^)default-push = default = http)/default-push = http/ {} +
    
  3. 有效 :-) 将默认的 http-String 替换为 ssh-String:

    find . -type f -name 'hgrc' -exec sed -i '' s/default = http:\\/\\/ourmercurialserver.de/ssh:\\/\\/default = myusername@ourmercurialserver.de\\/\\/path\\/to\\/repositories/ {} +
    

编辑:我的最终解决方案(感谢 Torek 和 meistermuh)

  1. 插入第二行默认推送

    find . -type f -name 'hgrc*' -exec sed -i '' -e 's,^default = http://\(.*\),default = http://nkoch@\1\
    default-push = http://\1,' {} +
    
  2. 将默认的 http-String 替换为 ssh-String

    find . -type f -name 'hgrc' -exec sed -i '' 's,^default = http://myusername@ourmercurialserver.de,default = ssh://myusername@ourmercurialserver.de//path/to/repositories,' {} +
    

【问题讨论】:

  • (^) 和 ($) 可能是个问题。只需删除括号,因为您不需要并且实际上也不能对 0 字节信号进行分组(^ 和 $ 实际上不是字符等,而是一种用于“行首”和“行尾”的信号)跨度>
  • 感谢您的快速回复。 (^) 和 ($) 是否存在并不重要。我总是收到错误“-bash: 意外标记 `('”附近的语法错误将在原始帖子中阐明
  • 啊,好的,我明白了。将您的替换放在单引号中,并且仅在需要时使用圆括号对模式进行分组。示例:find . -type f -name 'hgrc' -exec sed -i '' 's/^default-push = default = http)/default-push = http/' {} + 在您的第一个示例中,\n 也会导致问题,因为文件名中不允许换行。顺便说一句:我目前不知道为什么你的第三个正在工作,因为你替换之前的空单引号(在每个示例中)接缝​​对我来说是错位的
  • 在尝试之前最重要的是:复制文件以进行备份;)

标签: regex http ssh find mercurial


【解决方案1】:

(注意:这并不是真正的 Mercurial 问题,它主要只是一个 shell 和 sed 问题,带有正则表达式的副作用。不过,如果你想变得特别花哨,你可能想确保只有paths 部分中的default = http://...被修改了,这需要在sed 中进行更多的工作,或者使用真正的配置文件阅读器。)

这里有多个问题:

  1. shell 喜欢解释和/或吃掉某些字符。

    具体细节取决于您使用的外壳。不过,大多数 shell 都有一个简单的约定:双引号引用单引号,并引用一些其他特殊字符,例如 *,但 不要 引用变量名扩展,例如 $var 和其他 @987654328基于 @ 的扩展,例如 $(subcommand)。同时,单引号引用 everything 除了单引号。 (并且,在任一类型的引号之外,反斜杠引用 one 字符,包括另一个反斜杠或任一类型的引号,因此如果您只需要输入一个引号,\" 或 \' 将做这个伎俩。)

    括号是贝壳容易吃掉的字符之一,所以:

    echo (foo)
    

    不是一个有效的命令。您必须引用括号,例如:

    sh-3.2$ echo '(foo)'
    (foo)
    

    或:

    sh-3.2$ echo \(foo\)
    (foo)
    

    请注意,对于\(echo 命令只能看到括号——在echo 运行时,反斜杠已消失(被shell 吃掉了)。

  2. sed 需要在必须捕获的正则表达式周围看到\(...\)。这些是文字反斜杠和括号。替换也是如此。整个s/match/replace/ 序列必须是一个单词。因此这是可行的:

    sh-3.2$ echo test | sed -e s/\\\(e.\*\\\)/captured\ \\\1/
    tcaptured est
    

    但它更具可读性:

    sh-3.2$ echo test | sed -e 's/\(e.*\)/captured \1/'
    tcaptured est
    

    在这里使用单引号意味着我们可以使用除单引号之外的任何内容。这允许我们在需要时使用$。这里没有必要(因为.*"maximal-munch"),但一般来说,如果你不想$ 插值,无论如何你都应该使用单引号。

  3. 如果您的目标是替换以下内容的行:

    default = http://whatever
    

    行,你有一点问题。让我们从更简单的开始:

    sh-3.2$ echo test | sed -e 's/\(e.*\)/
    > captured \1/'
    sed: 1: "s/\(e.*\)/
    captured \1/
    ": unescaped newline inside substitute pattern
    

    sed 的这个特殊变体(在我的 Mac 上)需要在换行符之前看到一个反斜杠。因此:

    sh-3.2$ echo test | sed -e 's/\(e.*\)/\
    captured \1/'
    t
    captured est
    

    sed 的其他变体可能允许不带反斜杠前缀的换行符。)

  4. (次要)我们可能希望在模式中使用/。我们可以写成,例如s/foo\/bar/foo2\/bar2/。幸运的是,我们不必使用s/foo/bar/,我们可以使用任何其他不会出现在模式中的字符,例如s,foo/bar,foo2/bar2,

幸运的是 find 不会直接将参数传递给 shell。如果是这样,您将遇到第五个问题,但我们现在已经涵盖了所有问题。 :-) 我们现在可以先编写一个有效的sed 命令并对其进行测试:

sh-3.2$ echo default = http://foo > foo.txt
sh-3.2$ sed -e 's,^default = http://\(.*\),default = ssh://myusername@\1\
> default-push = http://\1,' < foo.txt
default = ssh://myusername@foo
default-push = http://foo

这似乎可行,所以现在我们可以让命令通过添加-i '' 来进行就地编辑:

sh-3.2$ sed -i '' -e 's,^default = http://\(.*\),default = ssh://myusername@\1\
default-push = http://\1,' foo.txt
sh-3.2$ cat foo.txt
default = ssh://myusername@foo
default-push = http://foo

注意:我使用了您的“想要的结果”文本中的示例,这与问题主题中的示例相矛盾。确保您的最终命令序列在运行之前想要执行它(或者,作为meistermuh suggested in a comment,保留备份—也许使用-i ''以外的其他东西!)。

【讨论】:

    猜你喜欢
    • 2021-06-07
    • 1970-01-01
    • 2020-05-20
    • 1970-01-01
    • 2021-09-02
    • 2022-10-07
    • 2016-01-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多