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

Python subprocess调用带参Bash脚本报错排查(对比硬编码成功场景)

排查REST API调用报错原因及解决方案

问题描述

我开发了一个通过Bash脚本调用curl从国家图书馆网站获取报纸信息的REST API,脚本支持两种运行方式:

  • 直接执行bash sof.sh,使用硬编码参数,运行正常,可生成包含预期信息的JSON文件;
  • 通过Python的subprocess模块传递参数执行python file.py,运行报错,返回错误HTML页面。

Bash脚本内容(sof.sh)

#!/bin/bash

: '
################## 1) Running via Bash Script & hardcoding input arguments ##################
myQUERY="Rusanen"
myORDERBY="DATE_DESC"
myFORMATS='["NEWSPAPER"]'
myFUZZY="false"
myPubPlace='["Iisalmi", "Kuopio"]'
myLANG='["FIN"]'
################## 1) Running via Bash Script & hardcoding input arguments ##################
# Result: OK! a json file with retreived expected information
'

#: '
################## 2) Running from python script with input arguments ##################
for ARGUMENT in "$@"
do
    #echo "$ARGUMENT"
     KEY=$(echo $ARGUMENT | cut -f1 -d=)
     KEY_LENGTH=${#KEY}
     VALUE="${ARGUMENT:$KEY_LENGTH+1}"
     export "$KEY"="$VALUE"
done
echo $# "ARGS:" $*
################## 2) Running from python script with input arguments ##################
# Result: Error!!
#'

out_file_name="newspaper_info_query_${myQUERY// /_}.json"

echo ">> Running $0 | Searching for QUERY: $myQUERY | Saving in $out_file_name"

curl 'https://digi.kansalliskirjasto.fi/rest/binding-search/search/binding?offset=0&count=10000' \
-H 'Accept: application/json, text/plain, */*' \
-H 'Cache-Control: no-cache' \
-H 'Connection: keep-alive' \
-H 'Content-Type: application/json' \
-H 'Pragma: no-cache' \
--compressed \
--output $out_file_name \
-d @- <<EOF
{   "query":"$myQUERY",
    "languages":$myLANG,
    "formats":$myFORMATS,
    "orderBy":"$myORDERBY",
    "fuzzy":$myFUZZY,
    "publicationPlaces": $myPubPlace
}
EOF

Python调用代码(file.py)

def rest_api_sof(params={}):    
    params = {'query':            ["Rusanen"], 
              'publicationPlace': ["Iisalmi", "Kuopio"], 
              'lang':             ["FIN"], 
              'orderBy':          ["DATE_DESC"], 
              'formats':          ["NEWSPAPER"], 
              }

    print(f"REST API: {params}")

    subprocess.call(['bash',
                     'sof.sh',
                     f'myFORMATS={params.get("formats", "")}',
                     f'myQUERY={",".join(params.get("query"))}',
                     f'myORDERBY={",".join(params.get("orderBy", ""))}',
                     f'myLANG={params.get("lang", "")}',
                     f'myPubPlace={params.get("publicationPlace", "")}',
                     ])

if __name__ == '__main__':
    rest_api_sof()

报错表现

执行python file.py后,输出的JSON文件中返回国家图书馆的错误HTML页面(内容见问题原文),而非预期的报纸信息JSON数据。

原因分析

  1. 参数格式不匹配:Python传递数组类型参数时,直接拼接成了Python列表格式(如['NEWSPAPER']),但API要求的是标准JSON数组格式(如["NEWSPAPER"]),导致请求体JSON语法错误。
  2. 参数缺失:Python代码未传递myFUZZY参数,Bash脚本中该变量未定义,生成的请求体JSON会出现语法漏洞。
  3. Bash参数解析缺陷:原脚本用cut -f1 -d=解析key=value参数,若参数值包含=会解析错误,且未对参数值的特殊字符做转义处理。

解决方案

1. 修改Python代码,生成标准JSON格式参数

使用json.dumps()将列表转为标准JSON数组字符串,同时补充缺失的myFUZZY参数:

import subprocess
import json

def rest_api_sof(params={}):    
    params = {
        'query':            ["Rusanen"], 
        'publicationPlace': ["Iisalmi", "Kuopio"], 
        'lang':             ["FIN"], 
        'orderBy':          ["DATE_DESC"], 
        'formats':          ["NEWSPAPER"], 
        'fuzzy':            "false"
    }

    print(f"REST API: {params}")

    # 格式化参数值:列表转为JSON数组字符串,普通值直接返回
    def format_param(value):
        if isinstance(value, list):
            return json.dumps(value)
        return value

    subprocess.call([
        'bash',
        'sof.sh',
        f'myFORMATS={format_param(params.get("formats", ""))}',
        f'myQUERY={format_param(params.get("query", ""))}',
        f'myORDERBY={format_param(params.get("orderBy", ""))}',
        f'myLANG={format_param(params.get("lang", ""))}',
        f'myPubPlace={format_param(params.get("publicationPlace", ""))}',
        f'myFUZZY={format_param(params.get("fuzzy", ""))}'
    ])

if __name__ == '__main__':
    rest_api_sof()

2. 优化Bash脚本的参数解析逻辑

改用正则表达式解析key=value参数,支持值中包含=的情况,并对双引号做转义处理:

#!/bin/bash

# 解析传入的key=value格式参数
for ARGUMENT in "$@"
do
    # 正则匹配key=value,兼容值中包含=的场景
    if [[ "$ARGUMENT" =~ ^([^=]+)=(.*)$ ]]; then
        KEY="${BASH_REMATCH[1]}"
        VALUE="${BASH_REMATCH[2]}"
        # 转义值中的双引号,避免Bash解析冲突
        VALUE="${VALUE//\"/\\\"}"
        export "$KEY"="$VALUE"
    fi
done

out_file_name="newspaper_info_query_${myQUERY// /_}.json"

echo ">> Running $0 | Searching for QUERY: $myQUERY | Saving in $out_file_name"

curl 'https://digi.kansalliskirjasto.fi/rest/binding-search/search/binding?offset=0&count=10000' \
-H 'Accept: application/json, text/plain, */*' \
-H 'Cache-Control: no-cache' \
-H 'Connection: keep-alive' \
-H 'Content-Type: application/json' \
-H 'Pragma: no-cache' \
--compressed \
--output "$out_file_name" \
-d @- <<EOF
{   "query":"$myQUERY",
    "languages":$myLANG,
    "formats":$myFORMATS,
    "orderBy":"$myORDERBY",
    "fuzzy":$myFUZZY,
    "publicationPlaces": $myPubPlace
}
EOF

验证步骤

  1. 注释Bash脚本中的硬编码参数代码块,启用参数解析代码块;
  2. 执行python file.py,此时生成的请求体JSON格式与硬编码场景完全一致,API将返回正常的报纸信息JSON数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 21:10:19