用另一个文件的内容替换文件中的一行文本

用另一个文件的内容替换文件中的一行文本

我有两个文件,我们把它们称为foo.pyfixed_rule_map。我需要:

  • foo.py查找包含模式 的行rule_map =。如果这样更简单,那么找到模式 就足够了,但是由于包含 的rule_map行不止一行,因此在这种情况下我只需要匹配第一个匹配项。foo.pyrule_map
  • foo.py用 的内容fix_rule_map_in_foo(包含一行文本)替换 中的行。

例如foo.py可能看起来像这样:

class example:
    """some useless text.
    
    """
    rule_map = {'greater': lambda x, y: x > y, 'less': lambda x, y: x < y}

    def __init__(self,
                rule=None,
                ):
        self._init_rule(rule)


    def _init_rule(self, rule):
        if rule not in self.rule_map and rule is not None:
            raise KeyError(f'rule must be greater, less or None, '
                           f'but got {rule}.')
        self.rule = rule
        if self.rule is not None:
            self.compare_func = self.rule_map[self.rule]

我想将其更正如下:

class example:
    """some useless text.
    
    """
    rule_map = {'greater': lambda x, y: (x if x is not None else -inf) > (y if y is not None else -inf), 'less': lambda x, y: (x if x is not None else -inf) < (y if y is not None else -inf)}

    def __init__(self,
                rule=None,
                ):
        self._init_rule(rule)


    def _init_rule(self, rule):
        if rule not in self.rule_map and rule is not None:
            raise KeyError(f'rule must be greater, less or None, '
                           f'but got {rule}.')
        self.rule = rule
        if self.rule is not None:
            self.compare_func = self.rule_map[self.rule]

因此fixed_rule_map将是包含

    rule_map = {'greater': lambda x, y: (x if x is not None else -inf) > (y if y is not None else -inf), 'less': lambda x, y: (x if x is not None else -inf) < (y if y is not None else -inf)}

笔记因为foo.py是 Python 文件,所以替换必须保留缩进。

执行替换的命令必须放在 Dockerfile 中,因为必须在构建 Docker 映像时执行替换。Docker 使用/bin/sh作为 RUN 命令的解释器,而不是/bin/bash,如果您的解决方案使用,这可能会出现问题bash。但是,我认为我可以使用 shell 脚本来解决这个问题fix_rule_map_in_foo.sh

#! /bin/bash
FOO_PATH = /path/to/foo
<your_solution>

并在 Dockerfile 中添加此行:

RUN fix_rule_map_in_foo.sh

答案1

您可以使用 sed 编辑器的r命令读取文件的内容并插入,删除后面的原始匹配行:

sed -e '/rule_map = /{r fix_rule_map_in_foo' -e 'd;}' foo.py

默认情况下,新内容将写入标准输出,但 GNU sed 支持就地编辑标志(--in-place-i)。

由于这不涉及任何 shell 构造,因此我思考你可以直接运行它(虽然我不使用docker,所以不确定):

RUN sed -i.bak -e '/rule_map = /{r fix_rule_map_in_foo' -e 'd;}' foo.py

然而,如果您愿意的话,您也可以将其放入 POSIX shell 脚本中。

或者,使用非流编辑器ed(此使用 shell 构造,因此必须在脚本中):

#!/bin/sh

printf '%s\n' '/rule_map = /r fix_rule_map_in_foo' '-1d' 'wq' | ed -s foo.py

答案2

您可以使用命令替换将文件中包含的单行设置fix_rule_map_in_foo为名为 eg 的变量,fix如下所示:

fix="$(cat fix_rule_map_in_foo)"

如果愿意,您也可以将变量设置为固定字符串(而不是从文件中读取该字符串)像这样:

fix="The substitution string here"

然后将该变量传递给,awk以便您可以匹配该行并像这样替换它:

awk -v fix="$(cat fix_rule_map_in_foo)" '/rule_map = / {$0 = fix}1' foo.py

这将搜索rule_map =并替换包含与变量值匹配的行fix,并打印所有行(修改后)到终端...您可以根据需要将输出重定向到文件,例如>

如果您希望编辑文件foo.py,请像这样使用 GNU awk:

gawk -i inplace -v fix="$(cat fix_rule_map_in_foo)" '/rule_map = / {$0 = fix}1' foo.py 

相关内容