我正在尝试使用 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',
]
请注意,上面的代码使用前一行使用的任何缩进插入新文本。