带变量的Sed不能按我想要的方式工作

2024-10-01 05:06:26 发布

您现在位置:Python中文网/ 问答频道 /正文

('cd /etc/squid/ && new_val=9 && old_val=3 && sed -i "s/$old_val/$new_val/g" *.conf')

这给了我一个错误

ExecutionError: sed: -e expression #1, char 0: no previous regular expression

我不知道是什么问题。在

上面的代码正在Python脚本中使用。在


Tags: nonewconf错误etccdvalsed
3条回答

事实上,我找到了一些有用的方法,将每个变量放在单引号中,然后对单引号进行转义。在

你的问题是:

old_val=3 sed "s/$old_val/$new_val/g"

依赖于shell来扩展变量,而不是sed。但是通过命令前缀设置变量只会影响命令的环境,而不是bash,因此old_val从不为字符串插值而定义的。根据bash reference manual(加上强调):

The environment for any simple command or function may be augmented temporarily by prefixing it with parameter assignments, as described in Shell Parameters. These assignment statements affect only the environment seen by that command.

因此,如果sed试图从自己的环境中读取old_val,它将看到正确的值。但是sed接收的是传递的后插值字符串,它是s//9/g,因为bash插值没有看到old_val(它只存在于sed)。在

要修复此问题,请在bash中设置变量,方法是将赋值作为单独的命令执行,而不是sed前缀:

^{pr2}$

或者更准确地说,您应该真正避免依赖shell=True(这很危险/很容易被滥用)。即使必须使用sed,也可以在Python层完成使用shell的所有工作:

import os

# Get the (unqualified) names of all the entries with the desired name
files = [f for f in os.listdir('/etc/squid') if f.endswith('.conf')]
# Run w/o shell=True, in list form, letting Python handle the working directory
# and variable formatting
subprocess.Popen(['sed', '-i', 's/{}/{}/g'.format(old_val, new_val)] + files, cwd='/etc/squid')

这有相同的行为(在/etc/squid中操作,并传递不合格的文件名,这样如果在深度嵌套的目录中有很多文件,就不会出现新的命令行长度问题)。在

当然,您可以更进一步,只需在Python中使用the ^{} module来完成sed的工作;它的特点是像sed一样就地编辑文件(尽管如果文件的大小有意义,它可能会稍微慢一点)。在

更改为:

('cd /etc/squid/ && new_val=9 && old_val=3 && sed -i "s/$old_val/$new_val/g" *.conf')

变量赋值需要是sed的独立语句。当您在语句的开头放置变量赋值时,它只设置一个由子进程继承的环境变量。但是需要原始shell扩展变量,因此需要在执行sed命令之前设置变量。在

相关问题 更多 >