sed 模式匹配和插入文件

sed 模式匹配和插入文件

我正在尝试使用 sed 编辑setup.py文件,这是我需要匹配的模式:

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import fnmatch
import os
import re
import sys

from setuptools import Command
from setuptools import find_packages
from setuptools import setup
from setuptools.command.install import install as InstallCommandBase
from setuptools.dist import Distribution

DOCLINES = __doc__.split('\n')

_VERSION = '1.0.0'

REQUIRED_PACKAGES = [
    'absl-py >= 0.7.0',
    'astunparse == 1.6.3',
    'backports.weakref >= 1.0rc1;python_version<"3.4"',
    'scipy == 1.2.2;python_version<"3"',
]

匹配后我想在结束之前REQUIRED_PACKAGES = [ .* ]插入一行。'test == 1.1.0',]

所以最终看起来像这样:

REQUIRED_PACKAGES = [
    'absl-py >= 0.7.0',
    'astunparse == 1.6.3',
    'backports.weakref >= 1.0rc1;python_version<"3.4"',
    'scipy == 1.2.2;python_version<"3"',    
    'test == 1.1.0',
]

我尝试使用 Python,但寻找更干净、更简单的选择。

import re


SEARCH_DICT = {
    'required_packages': re.compile(
        r'REQUIRED_PACKAGES = (?P<required_packages>.*)\n')
}

TEST_LIBRARY = '\t\t\'test==1.0.0\'\n'


def _parse_line(line):
    """
    Do a regex search against all defined regexes and
    return the key and match result of the first matching regex

    """

    for key, rx in SEARCH_DICT.items():
        match = rx.search(line)
        if match:
            return key, match
    # if there are no matches
    return None, None


def parse_file(filepath):
    """
    Parse text at given filepath

    Parameters
    ----------
    filepath : str
        Filepath for file_object to be parsed

    Returns
    -------
    data : file contents
    """

    data = []  # create an empty list to collect the data
    line_index = -1 
    # open the file and read through it line by line

    with open(filepath, 'r+') as file_object:
        line = file_object.readline()
        line_index+=1
        while line:
            # at each line check for a match with a regex
            key, match = _parse_line(line)
            if key == 'required_packages':
                required_packages_start = match.group('required_packages')
                if required_packages_start == '[':                    
                    print('Found REQUIRED_PACKAGES')
                    while line.strip():                        
                        library = line.rstrip()
                        if library == ']': # End of required packages
                            return line_index
                        line = file_object.readline()
                        line_index+=1                     

            line = file_object.readline()  
            line_index+=1          
        file_object.readline()
        line_index+=1

    return line_index


line_index = parse_file('test.test')
lines = None
if line_index:
    with open('test.test', 'r') as file_handler:
        lines = file_handler.readlines()
    lines.insert(line_index, TEST_LIBRARY)
    with open('test.out', 'w') as file_handler:
        file_handler.writelines(lines)

答案1

sed可以i插入一行:

sed "/REQUIRED_PACKAGES = \[/, /]/ {/]/i\    'test == 1.1.0',
;}" FILE

答案2

sed是一个面向行的工具。我相信更好的是使用awk,它会更容易地检测到您想要的块并附加一行。可能有一种更优雅的方式,但这可以满足您的要求:

awk '$0=="REQUIRED_PACKAGES = [" {found=1}
    found==1 && $0=="]" {print "    \047test == 1.1.0\047"; found=0}
    {print}' setup.py

非常容易理解:它打印文件的每一行,但在打印块的右括号之前,REQUIRED_PACKAGES它会打印您要附加的行。

答案3

$ cat file
_VERSION = '1.0.0'

REQUIRED_PACKAGES = [
    'absl-py >= 0.7.0',
    'astunparse == 1.6.3',
    'backports.weakref >= 1.0rc1;python_version<"3.4"',
    'scipy == 1.2.2;python_version<"3"',
]

$ cat tst.awk
/REQUIRED_PACKAGES = \[/ { inBlock=1 }
inBlock {
    if ( /]/ ) {
        sub(/[^[:space:]].*/,"",prev)
        print prev "\047test == 1.1.0\047,"
        inBlock = prev = ""
    }
    prev = $0
}
{ print }

$ awk -f tst.awk file
_VERSION = '1.0.0'

REQUIRED_PACKAGES = [
    'absl-py >= 0.7.0',
    'astunparse == 1.6.3',
    'backports.weakref >= 1.0rc1;python_version<"3.4"',
    'scipy == 1.2.2;python_version<"3"',
    'test == 1.1.0',
]

请注意,上面的代码使用前一行使用的任何缩进插入新文本。

相关内容