执行kubectl exec时出现未终止引号字符串错误的求助
解决kubectl exec执行带引号命令的"Unterminated quoted string"错误
问题概述
通过Shell脚本执行kubectl exec,从YAML文件读取容器名、Pod名、待执行命令和输出文件名,用yq解析YAML。但带引号的命令执行时出现"Unterminated quoted string"错误,直接在命令行运行这些命令正常,存入变量执行则报错,修改引号类型无效。
原脚本函数
get_execs() { mkdir ${EXECDIR} for con in $(yq '.containers[] | .name' ${YFILE}) do # echo $con x=$(i=$con yq '.containers[] | select(.name == env(i)) | .collect_execs[] | .name' ${YFILE}) # printf \"%s\\n\" \"$x\" mkdir ${EXECDIR}/$con for j in $x do c=$(i=$con p=$j yq '.containers[] | select(.name == env(i)) | .collect_execs[] | select(.name == env(p)) | .cmd' ${YFILE}) pod=$(i=$con yq '.containers[] | select(.name == env(i)) | .pod' ${YFILE}) # printf \"%s abc\\n\" \"$c\" kubectl exec -n ${NAMESPACE} $pod -c $con -- $c > ${EXECDIR}/$con/$j done done }
YAML文件结构
containers: - name: otg-port-eth1-protocol-engine pod: otg-port-eth1 collect_execs: - name: resource-usage cmd: top -c -n 2 -b -H -w 120 - name : disk-space cmd : df -H - name: cpu-info cmd: cat /proc/cpuinfo - name: interface-manager-threads-iter1 cmd : sh -c 'gdb --eval-command \"set pagination 0\" --eval-command \"thread apply all bt\" --batch --pid $(pidof InterfaceManager)' - name: interface-manager-threads-iter2 cmd : sh -c 'gdb --eval-command \"set pagination 0\" --eval-command \"thread apply all bt\" --batch --pid $(pidof InterfaceManager)' - name: interface-manager-shared-sos cmd: sh -c 'cat /proc/$(pidof InterfaceManager)/maps' - name: netstat cmd: netstat -an - name: dmesg cmd : dmesg - name : ifconfig cmd : ifconfig
错误信息
--eval-command: 1: Syntax error: Unterminated quoted string command terminated with exit code 2 --eval-command: 1: Syntax error: Unterminated quoted string command terminated with exit code 2 /proc/$(pidof: 1: Syntax error: Unterminated quoted string command terminated with exit code 2 --eval-command: 1: Syntax error: Unterminated quoted string command terminated with exit code 2 --eval-command: 1: Syntax error: Unterminated quoted string command terminated with exit code 2 /proc/$(pidof: 1: Syntax error: Unterminated quoted string command terminated with exit code 2
问题根源
- 变量展开时引号丢失:带引号的命令存入单个变量后,Shell执行时会拆分参数但不重新解析引号,导致原命令的引号结构被破坏。
- for循环的空格拆分:
for con in $(yq ...)这类写法会将含空格的元素拆分成多个循环项,引发解析错误。 - YAML转义处理失效:YAML中的
\"转义引号在yq输出后,Shell无法正确识别为引号的一部分。
解决方案
步骤1:修改YAML命令为数组格式(推荐)
将复杂带引号命令改为字符串数组,避免转义问题,让Shell能正确识别每个参数:
containers: - name: otg-port-eth1-protocol-engine pod: otg-port-eth1 collect_execs: - name: resource-usage cmd: ["top", "-c", "-n", "2", "-b", "-H", "-w", "120"] - name : disk-space cmd : ["df", "-H"] - name: cpu-info cmd: ["cat", "/proc/cpuinfo"] - name: interface-manager-threads-iter1 cmd : ["sh", "-c", "gdb --eval-command \"set pagination 0\" --eval-command \"thread apply all bt\" --batch --pid $(pidof InterfaceManager)"] - name: interface-manager-threads-iter2 cmd : ["sh", "-c", "gdb --eval-command \"set pagination 0\" --eval-command \"thread apply all bt\" --batch --pid $(pidof InterfaceManager)"] - name: interface-manager-shared-sos cmd: ["sh", "-c", "cat /proc/$(pidof InterfaceManager)/maps"] - name: netstat cmd: ["netstat", "-an"] - name: dmesg cmd : ["dmesg"] - name : ifconfig cmd : ["ifconfig"]
步骤2:修改Shell脚本修复循环与参数传递
get_execs() { # 加-p参数避免目录已存在报错 mkdir -p "${EXECDIR}" # 用while read遍历容器名,避免空格拆分 yq '.containers[] | .name' "${YFILE}" | while read -r con; do mkdir -p "${EXECDIR}/${con}" # 遍历当前容器的所有collect_execs名称 yq '.containers[] | select(.name == env(i)) | .collect_execs[] | .name' "${YFILE}" i="${con}" | while read -r j; do # 将命令解析为数组 mapfile -t cmd_arr < <(yq '.containers[] | select(.name == env(i)) | .collect_execs[] | select(.name == env(p)) | .cmd[]' "${YFILE}" i="${con}" p="${j}") pod=$(yq '.containers[] | select(.name == env(i)) | .pod' "${YFILE}" i="${con}") # 用数组传递参数,保留原命令结构 kubectl exec -n "${NAMESPACE}" "${pod}" -c "${con}" -- "${cmd_arr[@]}" > "${EXECDIR}/${con}/${j}" done done }
关键改进点
- 用
while read -r替代for in $(...),避免空格拆分元素 - 用
mapfile -t将yq输出的命令参数存入数组,保留每个参数的完整性 - 所有变量用双引号包围,避免空格和特殊字符解析错误
- YAML命令改为数组格式,让yq直接输出独立参数,无需处理引号转义
备选方案(无需修改YAML)
若无法修改YAML,可使用eval执行命令(仅信任YAML内容时使用,存在注入风险):
# 替换原执行命令的行 eval "kubectl exec -n ${NAMESPACE} ${pod} -c ${con} -- ${c}" > "${EXECDIR}/${con}/${j}"
内容的提问来源于stack exchange,提问作者Alankriti
相关产品推荐
相关产品推荐

