记一段shell 脚本遇到的问题

最近写了一段shell 脚本, 执行过程中遇到一些错误, 这里记录一下.

脚本内容

脚本的用意是: 有 pod 在 kubenetes cluster 里面, 要去 profiling 里面 Java 进程. 所以要先 copy profiler 工具上去, 然后解压缩, 之后找到 Java 进程, 最后 profiling.

下面是改正后的脚本:

#!/bin/bash

#set -x
# Set variables
pod="my_pod_1"
ns="my_ns"
cluster_id="37"
local_profiler="~/work/tools/async-profiler-1.7.1-linux-x64.tar.gz"
base_cmd="/tmp/profiler.sh -e itimer -d 30 -o svg -f /mnt/data/profile_eric.log.html"
# -e alloc | -e lock, -t <tid>, --reverse

# Copy profiler to target pod
echo "Copying profiler to target pod"
kubectl cp "${local_profiler}" "${pod}:/tmp/async-profiler-1.7.1-linux-x64.tar.gz" -n "${ns}" --context="${cluster_id}" -c app

# Unzip the profiler
echo "Unzipping the profiler"
kubectl exec -it "${pod}" -n "${ns}" --context="${cluster_id}" -c app -- tar -xf /tmp/async-profiler-1.7.1-linux-x64.tar.gz -C /tmp/

# Get target pod's Java PID
pid=$(kubectl exec "${pod}" -n "${ns}" --context="${cluster_id}" -c app -- pgrep java)
echo "Target pod Java PID is ${pid}"

# Construct the full command
cmd="${base_cmd} ${pid}"
echo "Command is ${cmd}"

# Run profiling
echo "Running profiling"
kubectl exec "${pod}" -n "${ns}" --context="${cluster_id}" -c app -- ${cmd}

遇到的问题

所有的步骤都能被执行, 但是最后一行代码本应该执行 30 秒, 因为在 profiler 的参数里面设置了 -d 30, 可是每次profiling 工具都是开始执行, 立马结束. 打印执行的命令, 把命令单独执行, 也都没有问题.

问题原因

经过 Shell 脚本大师 Peter Deng 的指点, 加了 set -x 参数, 就可以看出到底执行到了哪一步. 发现在 profiler.sh 里面去 kill -0 $PID 的时候, 发现目标进程不存在, 就结束了. 仔细察看代码, 发现传入的进程号竟然是 $25\r, 但其实应该是25.

在进一步排查为什么是$25\r, 发现最初获取进程号的代码是:

pid=$(kubectl exec -it "${pod}" -n "${ns}" --context="${cluster_id}" -c app -- pgrep java)

里面有 -it, 那么它的返回就是 $25\r, 也就是先是一个命令开始符号, 接着是进程号输出, 然后换行. 这正是一般命令行的输出形式. 所以去掉 -it 就只返回进程号了.

另外一个离奇的是: 虽然变量值是 $25\r, 但是当用 echo 打印的时候, 它只显示 25.

验证

使用下面的代码验证:

#!/bin/bash

num="$34\r"
echo "the num is: ${num}"
echo "the num length is ${#num}"

执行输出的结果:

$sh test.sh
the num is: 4
the num length is 3

获得

  1. 使用 set -x 能帮助很快的去debug
  2. 在 $后面的字符很多都有转义, 要小心注意.

标签: none

添加新评论