You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无法通过Python脚本从流水线非交互式修改Linux虚拟机内文件

解决Python构造gcloud SSH命令修改远程文件的语法错误

问题描述

尝试通过Python构造gcloud命令修改Linux虚拟机内的config.properties文件时,频繁出现bash语法错误:

bash: -c: line 0: unexpected EOF while looking for matching `''
bash: -c: line 1: syntax error: unexpected end of file

相关代码如下:

def get_awk_command():
    return """cd /test/tlu; awk '{sub(/SampleUrl=.*/, "SampleUrl=https://google.com/api")}1' config.properties > config.tmp && mv config.tmp config.properties -f"""


async def update_config(args, project_name):
     update_config_command = get_awk_command().replace("'", r"'\''")
     gcp_command = f'gcloud compute ssh testuser@{VM_NAME} --project={project_name} --zone={vm_zone} --tunnel-through-iap --quiet --command=\"sudo bash -c {update_config_command}\"'
     process = subprocess.run(gcp_command, shell=True, capture_output=True)
     output =  process.stdout.decode('utf-8')

错误原因

问题出在多层命令嵌套的引号转义逻辑:

  1. 原代码中--command使用双引号包裹,内部的bash -c命令又包含转义后的单引号,导致bash解析时引号匹配混乱。
  2. 手动替换单引号的方式没有适配多层shell解析的需求,最终导致bash无法找到匹配的单引号。

解决方案

方案1:调整引号层级与转义逻辑

修改gcp_command的构造方式,用单引号包裹--command的参数,内部用双引号承载bash -c的命令,确保转义后的单引号能被正确解析:

def get_awk_command():
    return """cd /test/tlu; awk '{sub(/SampleUrl=.*/, "SampleUrl=https://google.com/api")}1' config.properties > config.tmp && mv config.tmp config.properties -f"""


async def update_config(args, project_name):
    # 为bash -c转义单引号:将'替换为'\''
    escaped_cmd = get_awk_command().replace("'", r"'\''")
    # 用单引号包裹整个--command参数,内部用双引号装bash -c的命令
    gcp_command = f"""gcloud compute ssh testuser@{VM_NAME} --project={project_name} --zone={vm_zone} --tunnel-through-iap --quiet --command='sudo bash -c "{escaped_cmd}"'"""
    # 使用text=True直接获取字符串输出,无需手动decode
    process = subprocess.run(gcp_command, shell=True, capture_output=True, text=True)
    output = process.stdout

方案2:使用参数列表避免shell解析(推荐)

放弃shell=True,改用subprocess.run的参数列表形式,配合shlex.quote自动处理转义,彻底避免引号嵌套问题,同时降低shell注入风险:

import shlex

def get_awk_command():
    return """cd /test/tlu; awk '{sub(/SampleUrl=.*/, "SampleUrl=https://google.com/api")}1' config.properties > config.tmp && mv config.tmp config.properties -f"""


async def update_config(args, project_name):
    # 用shlex.quote自动转义命令,适配bash -c的要求
    sudo_cmd = f"bash -c {shlex.quote(get_awk_command())}"
    # 构造gcloud命令的参数列表,无需shell解析
    gcp_args = [
        "gcloud", "compute", "ssh", f"testuser@{VM_NAME}",
        "--project", project_name,
        "--zone", vm_zone,
        "--tunnel-through-iap",
        "--quiet",
        "--command", sudo_cmd
    ]
    process = subprocess.run(gcp_args, capture_output=True, text=True)
    output = process.stdout

说明

方案2更推荐,因为:

  • 无需手动处理复杂的引号转义,减少人为错误
  • 避免shell=True带来的安全风险(如命令注入)
  • 代码可读性和可维护性更高

内容的提问来源于stack exchange,提问作者Joji Lawerence

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 21:28:40