【问题标题】:Sed with variables isn't working exactly how I want it to work带变量的 Sed 不能完全按照我希望的方式工作
【发布时间】:2017-07-14 16:20:17
【问题描述】:
('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 脚本中使用。

【问题讨论】:

  • 我知道我可以使用 subprocess 但我想知道我在这里缺少什么..
  • 从命令行对我来说很好。我怀疑 Python 可能是这里的问题。
  • @miken32:这不是 Python,而是对bash 的滥用。从命令行无法正常工作,简单复制:new_val=9 && old_val=3 sed "s/$old_val/$new_val/g" <(echo "1234567890")
  • @ShadowRanger 当我看到发送命令在单独的行上的问题时,因此感到困惑。我怀疑 Python,因为他们说它正在 Python 脚本中使用,这意味着它必须有比我们所看到的更多的上下文。

标签: python variables sed


【解决方案1】:

改成:

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

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

【讨论】:

    【解决方案2】:

    你的问题是:

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

    是依靠shell来扩展变量,而不是sed。但是通过命令前缀设置变量只会影响命令的环境,而不是 bash,所以old_val从不定义用于字符串插值。根据bash reference manual(已添加重点):

    任何简单命令或函数的环境都可以通过在其前面加上参数分配来临时扩充,如外壳参数中所述。这些赋值语句只影响那个命令看到的环境。

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

    要解决此问题,请通过将赋值作为单独的命令而不是 sed 前缀来设置 bash 中的变量:

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

    或者更准确地说,您应该真正避免依赖shell=True(它很危险/容易误用)。即使你必须使用sed,你使用 shell 的所有东西都可以在 Python 层完成:

    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 fileinput module 来完成sed 的工作;它的特点是可以像sed 一样编辑文件(尽管如果文件的大小有意义,它可能会稍微慢一些)。

    【讨论】:

      【解决方案3】:

      实际上我发现了一些可行的方法,将每个变量放在单引号中并转义单引号。

      【讨论】:

      • 你能解释/提供解决方案代码吗?我没有看到单引号在这里有帮助的明显方式(您可以使用它们来避免 bash 变量插值,但我不认为 sed 会为您做这件事,如果它收到 $ 名称,它只会将它们视为文字字符串)。
      猜你喜欢
      • 2021-05-29
      • 1970-01-01
      • 1970-01-01
      • 2022-12-13
      • 2018-10-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-13
      相关资源
      最近更新 更多