#!/bin/bash
# 脚本文件名：check_pid.sh
# 修订版本：1.1
# 日期：2025/01/21
# 作者：Jack.liu
# 电子邮件：lqf@xlsys.cn
# 网址：www.xlsys.cn
# 脚本功能描述：
# 这个脚本用于查询系统中的进程信息。
# 用户可以通过指定进程 ID (PID) 或进程名称来获取详细信息。

# 本脚本支持以下功能：
# 1. 用户可以指定一个数字作为 PID 获取对应的进程信息。
# 2. 用户可以指定一个进程名称来查询所有相关进程的信息。
# 3. 格式化显示内存大小（以 KB 、MB 、GB 为单位）。
# 4. 显示进程状态及其翻译（例如：运行中、休眠中等）。

# 输出信息包括：
# - 进程 PID
# - 进程命令
# - 用户
# - CPU 和内存占用率
# - 进程开始和运行时间
# - 进程状态
# - 虚拟内存和共享内存使用情况

# 打印使用说明函数
show_usage() {
  echo "Usage: $0 [pid|name]"
  echo ""
  echo "参数格式："
  echo "  [pid]     一个数字，表示要查询的进程 ID 。"
  echo "  [name]    一个字符串，表示要查询的进程名称。"
  echo ""
  echo "示例："
  echo "  $0 1234     查询 PID 为 1234 的进程信息"
  echo "  $0 sshd     查询名称为 sshd 的所有进程信息"
}

# 格式化内存大小函数，以便更好阅读
format_memory_size() {
  local value=$1
  if [ "$value" -lt 1024 ]; then
    echo "${value} KB"
  elif [ "$value" -lt 1048576 ]; then
    echo "$(awk "BEGIN {printf \"%.2f MB\n\", $value/1024}")"
  else
    echo "$(awk "BEGIN {printf \"%.2f GB\n\", $value/1048576}")"
  fi
}

# 翻译进程状态
translate_status() {
  local status=$1
  case $status in
    R) echo "R: 运行中（Running）";;
    S) echo "S: 休眠中（Sleeping）";;
    D) echo "D: 等待 IO（Uninterruptible Sleep）";;
    Z) echo "Z: 僵尸进程（Zombie）";;
    T) echo "T: 停止（Stopped）";;
    *) echo "$status: 未知状态（Unknown）";;
  esac
}

# 根据 PID 获取进程信息的函数
get_info_by_pid() {
  local PID=$1
  local process_info
  process_info=$(ps -aux | awk -v pid="$PID" '$2 == pid')

  if [[ -z "$process_info" ]]; then
    echo "该 PID 不存在！"
    exit 1
  fi

  echo "$process_info" | while read -r line; do
    user=$(echo "$line" | awk '{print $1}')
    pid=$(echo "$line" | awk '{print $2}')
    cpu=$(echo "$line" | awk '{print $3}')
    mem=$(echo "$line" | awk '{print $4}')
    start_time=$(echo "$line" | awk '{print $9}')
    elapsed_time=$(echo "$line" | awk '{print $10}')
    status=$(echo "$line" | awk '{print $8}')
    vmem=$(echo "$line" | awk '{print $5}')
    shared_mem=$(echo "$line" | awk '{print $6}')
    command=$(echo "$line" | awk '{print $11}')

    # 格式化内存大小
    vmem_formatted=$(format_memory_size "$vmem")
    shared_mem_formatted=$(format_memory_size "$shared_mem")

    # 显示带翻译的进程状态
    status_translated=$(translate_status "$status")

    # 输出进程信息
    printf "***************************************************************\n"
    printf "进程 PID: %s\n" "$pid"
    printf "进程命令：%s\n" "$command"
    printf "进程所属用户: %s\n" "$user"
    printf "CPU 占用率：%s%%\n" "$cpu"
    printf "内存占用率：%s%%\n" "$mem"
    printf "进程开始运行的时刻：%s\n" "$start_time"
    printf "进程运行的时间：%s\n" "$elapsed_time"
    printf "进程状态：%s\n" "$status_translated"
    printf "进程虚拟内存：%s\n" "$vmem_formatted"
    printf "进程共享内存：%s\n" "$shared_mem_formatted"
    printf "***************************************************************\n"
  done
}

# 根据进程名获取并格式化进程信息的函数
get_info_by_name() {
  local NAME=$1
  local processes
  processes=$(ps -aux | grep -v grep | grep "$NAME")

  if [[ -z "$processes" ]]; then
    echo "该进程名没有运行！"
    exit 1
  fi

  echo "$processes" | while read -r line; do
    user=$(echo "$line" | awk '{print $1}')
    pid=$(echo "$line" | awk '{print $2}')
    cpu=$(echo "$line" | awk '{print $3}')
    mem=$(echo "$line" | awk '{print $4}')
    start_time=$(echo "$line" | awk '{print $9}')
    elapsed_time=$(echo "$line" | awk '{print $10}')
    status=$(echo "$line" | awk '{print $8}')
    vmem=$(echo "$line" | awk '{print $5}')
    shared_mem=$(echo "$line" | awk '{print $6}')
    command=$(echo "$line" | awk '{print $11}')

    # 格式化内存大小
    vmem_formatted=$(format_memory_size "$vmem")
    shared_mem_formatted=$(format_memory_size "$shared_mem")

    # 显示带翻译的进程状态
    status_translated=$(translate_status "$status")

    # 输出进程信息
    printf "***************************************************************\n"
    printf "进程 PID: %s\n" "$pid"
    printf "进程命令：%s\n" "$command"
    printf "进程所属用户: %s\n" "$user"
    printf "CPU 占用率：%s%%\n" "$cpu"
    printf "内存占用率：%s%%\n" "$mem"
    printf "进程开始运行的时刻：%s\n" "$start_time"
    printf "进程运行的时间：%s\n" "$elapsed_time"
    printf "进程状态：%s\n" "$status_translated"
    printf "进程虚拟内存：%s\n" "$vmem_formatted"
    printf "进程共享内存：%s\n" "$shared_mem_formatted"
    printf "***************************************************************\n"
  done
}

# 检查命令行参数的有效性
if [[ $# -eq 0 ]]; then
  show_usage
  exit 1
fi

# 判断参数类型（数字表示 PID，非数字表示进程名）并调用相应函数
if [[ $1 =~ ^[0-9]+$ ]]; then
  get_info_by_pid "$1"
else
  get_info_by_name "$1"
fi