shell 将文件的多行部分替换为多行字符串,其中包含特殊字符和转义序列

wwodge7n  于 11个月前  发布在  Shell
关注(0)|答案(1)|浏览(133)

我有一个文件,它有一个像下面这样的部分,只提供了一个键/值对,但可能有N个数字:

"Section Name"
    {
        "Key"       "{\"foo\":[\"bar\"],\"one\":\"two\"}"
        "AnotherValue"      "I am a string"
    }

字符串
使用Bash,我可以提取,解析和操作我想要的块,并可以将操作的值存储在一个字符串中,看起来像这样:

"Section Name"
    {
        "Key"       "{\"changed\":[\"value\"],\"three\":\"two\"}"
        "AnotherValue"      "Updated string"
    }


节中的值是任意的,尽管它们总是用引号括起来。有许多JSON化的字符串,但也有许多明文字符串。这只是一个示例,块的内容可以完全清空,包含完全不同的值,等等。块可能不包含任何特殊字符,或者可以包含key/value pays,值简单地为""(尽管它总是,至少,是空引号)。
我需要使用Bash和标准的GNU Shell utils,用操作过的块更新源文件的原始块,完全如图所示,使用精确的转义序列。它应该在文件中与原始块相同的位置,只是替换它。
如果文件读起来像这样:

"Blank Section 1"
    {
    }
    "Section Name"
    {
        "Key"       "{\"foo\":[\"bar\"],\"one\":\"two\"}"
        "AnotherValue"      "I am a string"
    }
    "Blank Section 2"
    {
    }


更新后的文件应该是这样的:

"Blank Section 1"
    {
    }
    "Section Name"
    {
        "Key"       "{\"changed\":[\"value\"],\"three\":\"two\"}"
        "AnotherValue"      "Updated string"
    }
    "Blank Section 2"
    {
    }


我把源代码块和操作代码块都存储为变量,如果需要的话,也可以使用更新部分的开始和结束行作为模式来替换。
我试过分别使用sedawk来完成这个任务,但都没有成功,各种解决方案都在尝试使用具有这些转义特殊字符的值。如果我修改要转义的输入字符串,我可以让sed工作,但我需要保留整个文件内容,只需要用另一个块替换一个块。
我可以假设块的开始和结束模式在块被操作时不会改变,块内容是唯一会改变的东西,我可以假设它们将始终遵循这种格式:一个从基本缩进量缩进的制表符,用引号包围的键,两个制表符,然后是一个用引号包围的值,任意值(字符串化的JSON blob或类似的将被转义)。
需要说明的是,我并不是在问如何操作代码块。我已经这样做了。我只需要一种方法来用更新后的代码块替换原始代码块,保留所有转义字符,如图所示。我已经将确切的源代码和确切的操作代码块存储在变量中,我只需要用更新后的代码块替换源代码块。
基于原始文件的行号进行替换是可以接受的,例如删除X行和Y行之间的所有内容,然后在X行上插入更新的块。同样,将开始行和结束行作为模式进行替换也是完全可以接受的。只要原始块被新块覆盖,转义序列就完全按照所示的那样保留(如果存在的话),其余的文件内容仍然存在,但不受影响,所有这些都是用标准的Bash和GNU实用程序完成的,任何解决方案对我来说都是有效的。
数据格式是Valve基于文本的VDF格式,用于localconfig.vdfconfig.vdf(不同于用于appinfo.vdfshortcuts.vdf的二进制格式)。我知道它可以用其他语言(如Python)解析和操作,但我已经操作了字符串。我只需要用新的字符串块更新文件。
谢谢你,谢谢

qcbq4gxm

qcbq4gxm1#

如果要处理的文件足够小(我预计1 MB以下没有问题,根据系统的不同,大得多的文件也可以),那么Bash内置的字符串替换就可以满足你的需要。下面这段Shellcheck-clean代码演示了这个想法:

#! /bin/bash -p

oldsec='"Section Name"
{
    "Key"       "{\"foo\":[\"bar\"],\"one\":\"two\"}"
    "AnotherValue"      "I am a string"
}'

newsec='"Section Name"
{
    "Key"       "{\"changed\":[\"value\"],\"three\":\"two\"}"
    "AnotherValue"      "Updated string"
}'

old_file_contents=$(< file.txt)
new_file_contents=${old_file_contents//"$oldsec"/"$newsec"}

printf '%s\n' "$new_file_contents" >file.txt

字符串

  • 参见替换字符串的一部分(BashFAQ/100(如何在bash中进行字符串操作?))以获得${old_file_contents//"$oldsec"/"$newsec"}的解释。

相关问题