一次对参数的子集运行 sed



我目前正在python子进程中运行sed,但是我收到错误:

"OSError: [Errno 7] Argument list too long: 'sed'"

Python 代码是:

subprocess.run(['sed', '-i',
'-e', 's/#/pau/g',
*glob.glob('label_POS/label_phone_align/dump/*')], check=True)

其中/dump/目录中有 ~13,000 个文件。有人告诉我,我需要为参数列表的子集运行命令,但我找不到如何做到这一点。

谁告诉你这可能意味着你需要拆分 glob 并运行多个单独的命令:

files = glob.glob('label_POS/label_phone_align/dump/*')
i = 0
scale = 100
# process in units of 100 filenames until we have them all
while scale*i < len(files):
subprocess.run(['sed', '-i',
'-e', 's/#/pau/g',
*files[scale*i:scale*(i+1)]], check=True)
i += 1

然后在事后合并所有您需要的输出。我不知道sed命令可以从命令行接受多少输入,但显然不到 13,000 个。您可以不断更改scale直到它没有错误。

请向下滚动到此答案的末尾,以获取我为您的特定问题推荐的解决方案。这里有一些上下文和/或未来的访问者正在努力解决其他"参数列表太长"错误的背景。

exec()系统调用有大小限制;不能将超过ARG_MAX个字节作为参数传递给进程,在现代系统上,通常可以使用getconf ARG_MAX命令查询此系统常量的值。

import glob
import subprocess
arg_max = subprocess.run(['getconf', 'ARG_MAX'],
text=True, check=True, capture_output=True
).stdout.strip()
arg_max = int(arg_max)
cmd = ['sed', '-i', '-e', 's/#/pau/g']
files = glob.glob('label_POS/label_phone_align/dump/*')
while files:
base = sum(len(x) for x in cmd) + len(cmd)
for l in range(len(files)):
base += 1 + len(files[l])
if base > arg_max:
l -= 1
break
subprocess.run(cmd + files[0:l+1], check=True)
files = files[l+1:]

当然,xargs命令已经为您完成了此操作。

import subprocess
import glob
subprocess.run(
['xargs', '-r', '-0', 'sed', '-i', '-e', 's/#/pau/g'],
input=b''.join([x.encode() for x in glob.glob('label_POS/label_phone_align/dump/*') + ['']]),
check=True)

不过,在您的情况下,简单地删除长路径可能就足够了。您在参数数组中的每个文件名前面重复label_POS/label_phone_align/dump/

import glob
import subprocess
import os
path = 'label_POS/label_phone_align/dump'
files = [os.path.basename(file)
for file in glob.glob(os.path.join(path, '*'))]
subprocess.run(
['sed', '-i', '-e', 's/#/pau/g', *files],
cwd=path, check=True)

最终,也许更喜欢纯粹的Python解决方案。

import glob
import fileinput
for line in fileinput.input(glob.glob('label_POS/label_phone_align/dump/*'), inplace=True):
print(line.replace('#', 'pau'))

最新更新