【windows+android】shell批量推送数据+保存

function help_message() {
  cat <<EOF
Description: 根据GT的csv文件在Android上测试SDK,并保存日志
             1. 关于sdk,默认上传到/data/local/tmp目录下。若已经存在,则直接使用。
             2. 关于设备,存在多个在线设备时,必须指定一个设备序列号。
             3. 关于并发数,下载、推送文件、执行test_×××等都会并发。
             4. 关于日志,默认保存在当前目录下,目录名称包含GT文件名。
             5. 关于初始行号,会从初始行号开始执行测试到最后一行。
             6. 关于测试数据,优先使用当前目录下同路径的文件,如果没有则会从服务器上下载。
             7. 关于推送到设备上的测试数据,每次执行完成后都会删除。

Usage: bash $(basename "$0") -g <gt_file> -s <sdk> [options...]
Options:
        -g <gt_file>                  # GT的csv文件。必需
        -s <sdk>                      # 本地sdk目录。必需
        -d <device_serial>            # 设备序列号。非必需。有多个在线设备时必需指定
        -c <concurrent_num>           # 并发数。非必需。默认为1
        -l <log_path>                 # 日志保存路径。非必需。默认当前目录
        -i <init_line>                # GT文件初始行号。非必需。默认为2,跳过第一行表头
        -h                            # 帮助信息
EOF
}

if [[ $# -eq 0 ]]; then help_message && exit 1; fi # $#表示传入的参数个数

# 日志打印
function log_error() {
  printf "%b\n" "\033[1;31m$*\033[0m"
}

function log_info() {
  printf "%b\n" "\033[0;32m$*\033[0m"
}

function log_warn() {
  printf "%b\n" "\033[0;33m$*\033[0m"
}

concurrent_num=1 # 并发数默认值
init_line=2      # 初始行号默认值
#url=http://10.151.5.190:7670/ # 下载测试文件的地址
url=http://savvcenter.sensetime.com/resource

while getopts ":g:s:d:c:l:i:h" opt; do # 脚本参数
  case $opt in
  g)
    gt_file=${OPTARG} # GT的csv文件
    if [[ ! -f "${gt_file}" ]]; then
      log_error "文件不存在: ${gt_file}" && exit 1
    fi
    ;;
  s) sdk=${OPTARG} ;; # 本地sdk目录
  d)
    device_serial=${OPTARG} # 设备序列号
    if ! adb devices | awk '$NF~/device/{print $1}' | grep -iwq "${device_serial}"; then
      log_error "设备未连接或不在线: ${device_serial}" && exit 1
    fi
    ;;
  c) concurrent_num=${OPTARG} ;; # 并发数
  l) log_path=${OPTARG} ;;       # 日志保存路径
  i) init_line=${OPTARG} ;;      # GT文件初始行号
  h) help_message && exit ;;     # 帮助
  *) ;;
  esac
done

# 补充校验传入脚本的参数,并初始化变量
function check_param_and_init() {
  # GT文件和sdk目录不能为空
  if [[ -z ${gt_file} ]] || [[ -z ${sdk} ]]; then help_message && exit 1; fi

  # 支持不指定脚本参数中的设备,且只在线一个设备时,默认使用该设备
  if [[ -z ${device_serial} ]]; then                            # 如果该变量为空,即没有传该参数
    device_serial=$(adb devices | awk '$NF~/device/{print $1}') # 获取连接的设备
    device_num=$(wc -l <<<"${device_serial}")                   # 统计连接的设备数量
    if [[ ${device_num} -eq 0 ]]; then
      log_error "没有在线设备" && exit 1
    elif [[ ${device_num} -gt 1 ]]; then
      log_error "当前连接了多个设备,需指定一个设备:" "\n${device_serial}" && exit 1
    fi
  fi

  # 日志保存路径。${gt_file##*/}表示截取文件名
  if [[ -z ${log_path} ]]; then
    _time=$(date +'%Y_%m%d')
    log_path="${_time}_${gt_file##*/}_log"
    mkdir -p "${log_path}"
  fi

  remote_sdk="/data/local/tmp/$(basename "${sdk}")" # 设备上的sdk路径
  total_line=$(awk 'END {print NR}' "${gt_file}")   # GT文件总行数
}

# 上传初始化sdk
function init_sdk() {
  adbs root && adbs remount # 获取root权限和system分区可写权限
  log_info "开始推送sdk..."
  local env_file='env.sh'

  if ! adbs exec-out "ls ${remote_sdk}" | grep -iwq 'No such file or directory'; then # 检查sdk是否已推送过
    log_info "sdk已在设备上: ${remote_sdk}"
  elif [[ ! -d ${sdk} ]]; then
    log_error "sdk不存在: ${sdk}" && exit 1
  elif ! find "${sdk}" -name "${env_file}" | grep -iwq -m 1 "${env_file}"; then # 查找是否有env.sh文件
    log_error "sdk缺少${env_file}文件: ${sdk}" && exit 1
  elif ! adbs push "${sdk}" "${remote_sdk}"; then # 推送sdk到设备上
    log_error "sdk推送失败: ${sdk}" && exit 1
  fi

  # 获取设备上env.sh文件路径,即sdk运行根路径
  if env_path=$(adbs exec-out "find ${remote_sdk} -name ${env_file}" | sort -n | grep -w -m 1 "${env_file}"); then
    pre_command="cd $(dirname "${env_path}") && source env.sh && ./samples_CAPI/bin/" # 执行测试的前置命令
  else
    log_error "设备上的sdk缺少${env_file}文件: ${remote_sdk}" && exit 1
  fi

  adbs exec-out "chmod 777 -R ${remote_sdk}" # 修改权限,否则无法执行
}

# 打印任务信息
function print_task_info() {
  printf "%s\n" "
|设备: ${device_serial}
|并发数: ${concurrent_num}
|GT文件: ${gt_file}
|测试行数: ${init_line} - ${total_line}
|sdk路径: ${remote_sdk}
|log路径: ${log_path}
"
}

# 初始化并发数
function init_concurrent() {
  _fifo_file="$$.fifo"  # $$表示当前执行文件的PID
  mkfifo ${_fifo_file}  # 创建FIFO管道文件
  exec 6<>${_fifo_file} # 将文件描述符fd6和管道文件绑定
  rm -rf ${_fifo_file}  # 删除FIFO管道文件

  # 通过循环对文件描述符fd6写入空行,每行代表一个可并发的后台进程数量
  for _ in $(seq "${concurrent_num}"); do printf "\n" >&6; done
}

# 关闭文件描述符和管道的读写
function close_pipe() {
  exec 6>&- # 关闭文件描述符的写
  exec 6<&- # 关闭文件描述符的读
}

# 简化adb -s的使用
function adbs() {
  adb -s "${device_serial}" "$@"
}

# 清理日志等,释放硬盘空间
function clear_android_log() {
  log_warn "开始清理设备上的日志..."
  adbs exec-out "rm -rf /storage/emulated/0/*log"
  adbs exec-out "rm -rf /data/media/0/*log"
  adbs exec-out "rm -rf /mnt/runtime/*/emulated/0/*log" # 第一个*包含default、read、write
  adbs exec-out "rm -rf /mnt/runtime/*/emulated/0/bufferIn.pcm"
  adbs exec-out "rm -rf /mnt/runtime/*/emulated/0/Car*Video"
}

# 将文件推送到设备上,如果本地没有则下载
function push_file() {
  local local_file="./$1" # 默认为当前目录下的本地文件
  if [[ -f $1 ]]; then    # 如果绝对路径的文件存在,则使用绝对路径
    local_file=$1
  elif [[ ! -f "./$1" ]]; then  # 如果绝对路径不存在,且当前目录下文件也不存在
    mkdir -p "${local_file%/*}" # 创建文件夹。${local_file%/*}表示截取文件目录
    log_info "${progress} 开始下载文件: $1"
    if ! curl -f --connect-timeout 60 "${url}/${local_file}" -o "${local_file}"; then
      log_error "${progress} 文件下载失败: $1"
      rm -rf "${local_file}" # 删除未下载完成的本地文件。有trap时,即使按Ctrl+C也会执行
      return 1
    fi
  fi

  log_info "${progress} 开始推送文件: ${local_file}"
  if ! adbs push "${local_file}" "$2"; then
    log_error "${progress} 文件推送失败: ${local_file}" && exit 1
    #    clear_android_log
  fi
}

# 根据GT文件的第二列classification生成完整的测试命令
function generate_command() {
  local keywords file
  keywords=$(tr '[:upper:]' '[:lower:]' <<<"$1") # 转换为全小写
  file="$2"

  if [[ ${keywords} == *register* ]]; then
    #    test_command="test_FaceID ${file} 30 0 0 face.db"      # B561 主驾注册
    #    test_command="test_FaceID ${file} 30 0 1 face.db"      # B561 副驾注册
    test_command="test_FaceID 0 ${file} 30 face.db . 30 0" # P789 注册
  elif [[ ${keywords} == *login* ]]; then
    #    test_command="test_FaceID ${file} 30 1 0 face.db"      # B561 主驾登录
    #    test_command="test_FaceID ${file} 30 1 1 face.db"      # B561 副驾登录
    #    test_command="test_FaceID ${file} 30 1 3 face.db"      # B561 车外登录
    test_command="test_FaceID 1 ${file} 30 face.db . 30 0" # P789 登录
  elif [[ ${keywords} == *liveness* ]]; then
    # 活体必须要人脸特征值的文件,且文件中的值正确
    #    adbs exec-out "printf %s\n test_liveness > ${remote_sdk}/liveness.db" # 创建face.db文件,并写入数据
    test_command="test_FaceID ${file} 1 1 2 liveness.db" # B561 活体-图片-前排
    #    test_command="test_FaceID 1 ${file} 1 liveness.db . 1 1"              # JMC 活体-图片
    #    test_command="test_FaceID 1 ${file} 30 liveness.db . 30 0" # JMC 活体-图片
  else
    test_command="test_OMS ${file} 30 oms" # B561 OMS
    #    test_command="test_DMS ${file} 30"     # JMC DMS
  fi

  log_info "${progress} ${test_command}"
  full_command="${pre_command}${test_command}"
}

# 脚本异常时的安全退出操作
function safe_exit() {
  sleep 1
  log_warn "--------------------------------- 收到终止信号,安全退出中 ---------------------------------"
  sleep 2
  exit
}

# 执行测试 --------------------------------------------------------------------------------------------------------------
check_param_and_init
print_task_info

# INT 按下Ctrl+C发出;HUP 终端断开或用户退出时发出;QUIT 按下Ctrl+/发出;TERM 系统关机时发出
trap "safe_exit" SIGINT SIGHUP SIGQUIT SIGTERM
trap "wait; close_pipe; print_task_info" EXIT

init_sdk
init_concurrent

# 读取文件的每一行进行测试
awk "NR>=${init_line}" "${gt_file}" | while IFS=, read -r test_file classification _; do
  progress="[${init_line}/${total_line}]"
  read -r -u6 # 读取一个空行,代表消耗1个并发数
  {
    function teardown() {
      adbs exec-out "rm -rf ${remote_file}" # 删除推送的视频
      printf "\n" >&6                       # 写入一个空行,代表添加1个并发数
    }
    trap "" SIGINT SIGHUP SIGQUIT SIGTERM # 忽略异常退出的信号
    trap "teardown" EXIT

    # 替换路径后缀名为.log,并替换/为^。${test_file%.*}表示截取从左往右最后一个.左边的所有内容
    log_file="${log_path}/$(sed -e 's/\//^/g' <<<"${test_file%.*}.log")"
    if [[ -f "${log_file}" ]]; then # 日志文件已存在,跳过
      log_warn "${progress} 日志已存在: ${log_file}" && exit
    fi

    remote_file="${remote_sdk}/${test_file/\&/\\&}" # 处理特殊字符,将&替换为\&
    push_file "${test_file}" "${remote_file}" || exit 1

    generate_command "${classification}" "${remote_file}"     # 生成完整的测试命令
    if ! adbs exec-out "${full_command}" >"${log_file}"; then # 执行测试并保存日志文件到本地
      log_warn "${progress} 删除未完成日志: ${log_file}"
      rm -rf "${log_file}"
    fi
  } & # &表示将{}中的命令放到后台执行

  if [[ $(((init_line++))) -eq ${total_line} ]]; then wait; fi # 每次执行后行号加1,且最后一行时等待所有后台进程执行完毕
done

  • 8
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 批量推送公钥可以通过使用 SSH 的 authorized_keys 文件来实现。下面是一个示例脚本,可以将本地的公钥推送到多个远程主机上: ```bash #!/bin/bash # 设置需要推送的公钥文件路径 pubkey_path=~/.ssh/id_rsa.pub # 读取需要推送的主机列表 read -p "Enter remote hosts (separated by space): " hosts # 读取需要推送的用户 read -p "Enter remote user: " user # 循环遍历主机列表,将公钥复制到 authorized_keys 文件 for host in $hosts; do ssh $user@$host "mkdir -p ~/.ssh && chmod 700 ~/.ssh && touch ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys && cat >> ~/.ssh/authorized_keys" < $pubkey_path done ``` 在运行脚本时,会提示输入需要推送公钥的远程主机列表和远程用户,然后将本地的公钥文件复制到远程主机的 authorized_keys 文件中。注意,脚本需要在本地已经存在公钥文件,并且需要在远程主机上安装了 SSH 服务。 ### 回答2: 批量推送公钥是一种在多个远程服务器上自动化部署公钥的方法,可以方便地实现无需人工干预的SSH远程登录。 在Shell脚本中,我们可以使用以下的步骤来批量推送公钥: 1. 在脚本中定义一个包含远程服务器IP地址的数组,例如: ``` servers=("192.168.1.101" "192.168.1.102" "192.168.1.103") ``` 2. 使用一个循环结构来遍历数组中的IP地址,并执行以下操作: a. 生成公钥对(如果不存在的话): ``` if [ ! -f ~/.ssh/id_rsa.pub ]; then ssh-keygen -t rsa -q -N '' -f ~/.ssh/id_rsa fi ``` b. 使用ssh-copy-id命令将公钥拷贝到远程服务器: ``` ssh-copy-id user@$server ``` 其中,`user`是远程服务器登录的用户名,`$server`是当前遍历到的IP地址。 3. 将以上代码保存为一个Shell脚本文件(例如`push_keys.sh`),并添加执行权限。 4. 在终端中执行Shell脚本: ``` ./push_keys.sh ``` 这样,脚本将会自动遍历数组中的每个IP地址,生成并推送公钥到对应的远程服务器上。 需要注意的是,在执行ssh-copy-id命令时,可能会提示输入远程服务器的登录密码。为了避免这个问题,可以事先使用SSH Agent来管理私钥,或者在远程服务器上配置免密码登录。 希望以上回答对您有帮助! ### 回答3: Shell脚本批量推送公钥是一种方便快捷的方式,可以帮助用户在多台远程服务器上进行公钥的部署。下面是一个简单的Shell脚本示例: ``` #!/bin/bash # 指定要推送的公钥文件路径 public_key_file="path_to_public_key.pub" # 定义要连接的远程服务器列表 remote_servers=("server1" "server2" "server3") # 循环遍历远程服务器列表 for remote_server in "${remote_servers[@]}" do # 使用ssh-copy-id命令将公钥推送到远程服务器 ssh-copy-id -i $public_key_file $remote_server # 检查推送是否成功 if [ $? -eq 0 ] then echo "公钥已成功推送到服务器 $remote_server" else echo "公钥推送失败到服务器 $remote_server" fi done ``` 以上脚本假设您已经在本地生成了一个公钥文件,并且将路径存储在`public_key_file`变量中。您需要将`remote_servers`变量替换为您要推送公钥的实际远程服务器列表。 脚本中使用的`ssh-copy-id`命令可以将公钥复制到远程服务器的`~/.ssh/authorized_keys`文件中,完成公钥部署。在每个循环迭代中,脚本会检查命令的返回值来确定公钥是否成功推送到远程服务器。 使用这个Shell脚本,您可以轻松地在多台远程服务器上批量推送公钥,提高工作效率并加强服务器安全性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值