Bash: dchelper
dchelper.sh
#!/bin/bash # global variables # scriptDir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) scriptDir='' repositoryDir='' devopsHost='' dbHost='' logHost='' appHost='' workerHost='' rsaToken='' dcName='' flag='true' config='config' repositoryURL='git@github.wdf.sap.corp:sap-jam/instances.git' symbolicPath='/usr/local/bin/dchelper' filename='' # global variables # banner function banner() { # seq -s~ 106 | tr -d '[:digit:]' printf -- '~%.0s' $(seq 1 $(getScreenWidth)) echo echo -e "\033[34;47;7m^_^ Welcome to use dchelper tool, powered by Ares Team ^_^\033[0m" echo -e "\033[34;47;7m^_^ Any questions or concerns please feel free to contact xiaoyong.guo@sap.com / zheng.liu05@sap.com ^_^\033[0m" # seq -s~ 106 | tr -d '[:digit:]' printf -- '~%.0s' $(seq 1 $(getScreenWidth)) echo } function repeat() { for _ in $(seq 1 $2); do echo -n "$1" done } function getScreenWidth() { stty size | awk '{print $2}' } # getAbsoluteScriptDir function getScriptDir() { dirname "$(readlink -f "${BASH_SOURCE[0]}")" } function getConfigPath() { config="$scriptDir/config" } # normalize and return absolutePath function getAbsolutePath() { local _path="$1" while true; do if [[ "$_path" =~ /$ ]]; then # _path=${_path:0:-1} _path=${_path%?} else break fi done readlink -f "$_path" } function getSalveInstances() { local commence=$(cat -n $repositoryDir/instances/jam4.rb | grep "slave_instances" | awk '{print $1}') local list=$(cat -n $repositoryDir/instances/jam4.rb | grep "}" | awk '{print $1}') local closure=0 local i for i in $list; do if [[ $i -gt $commence ]]; then closure=$i break fi done let headn=$closure-1 let tailn=$closure-$commence-1 slaveInstances=$(cat $repositoryDir/instances/jam4.rb | head -n $headn | tail -n $tailn | awk -F':' '{ print $1}' | sed -e "s# ##g") echo ${slaveInstances[@]} } function findHost() { devopsHost=$(cat "$1" | grep -w devops_host | grep -v '^#' | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | head -1) dbHost=$(cat "$1" | grep -w db_slave_host | grep -v '^#' | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | head -1) echo $devopsHost-$dbHost } function findDBHost() { dbHost=$(cat "$1" | grep -w db_slave_host | grep -v '^#' | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | head -1) } function findLogHost() { logHost=$(cat "$1" | grep -w log_host | grep -v '^#' | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | head -1) echo $logHost } function findAppHost() { local line=$(cat -n "$1" | grep -w app_hosts | head -1 | cut -f1) let line++ appHost=$(cat "$1" | head -n $line | tail -n1 | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}') echo $appHost } function findWorkerHost() { local line=$(cat -n "$1" | grep -w worker_hosts | head -1 | cut -f1) let line++ workerHost=$(cat "$1" | head -n $line | tail -n1 | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}') echo $workerHost } function findAllSalveInstances() { local str='' local slaveInstance for slaveInstance in "$@"; do # echo $slaveInstance # echo "$repositoryDir/${slaveInstance}.rb" local filename="$repositoryDir/instances/${slaveInstance}.rb" if [ -f $filename ]; then str+="${slaveInstance}-$(findHost "$filename")-$(findLogHost "$filename")-$(findAppHost "$filename")-$(findWorkerHost "$filename")T" fi done # str=${str:0:-1} str=${str%?} echo ${str// /} } function findDC() { if [[ "$dcName" =~ ^stage|^integration ]]; then devopsHost=10.47.14.131 # dbHost=10.181.40.93 findDBHost "$filename" findLogHost "$filename" >&/dev/null findAppHost "$filename" >&/dev/null findWorkerHost "$filename" >&/dev/null flag=vigil return 0 fi local str=$(findHost "$filename") declare -a arr=(${str//-/ }) devopsHost=${arr[0]} dbHost=${arr[1]} findLogHost "$filename" >&/dev/null findAppHost "$filename" >&/dev/null findWorkerHost "$filename" >&/dev/null if [ "$dcName" != jam4 ]; then flag=false fi } function isGitWorkTree() { if [ ! -e "$1" ]; then echo -e "\033[31;47;7m$1 does not exist!\033[0m" exit 1 fi if ! [ -d "$1" ]; then echo -e "\033[31;47;7m$1 is not a directory!\033[0m" exit 1 # return 1 fi cd "$1" || exit if ! [[ $(git rev-parse --is-inside-work-tree 2>/dev/null) = true ]]; then echo -e "\033[31;47;7m$1 is not a git repository!\033[0m" exit 2 # return 2 fi cd - >&/dev/null || exit } function readConfig() { if ! [ -f "$config" ]; then return 1 fi awk -F'[ ]*=[ ]*' -v varname="$1" 'BEGIN{IGNORECASE=1} {if($1 ~ varname){print $2}}' $config } function saveConfig() { if ! [ -f "$config" ]; then touch $config fi if [ -z "$1" -o -z "$2" ]; then echo -e "\033[31;47;7mwrong arguments!\033[0m" exit 5 fi if grep -ioqs "^$1" $config; then # Mac OS is disgusting sed -r -i '' "/^$1/d" $config echo "$1 = $2" >>$config # sed -ir "#^$1#Ic $1 = $2" $config else echo "$1 = $2" >>$config # sed -ir "\$a $1 = $2" $config # need to escape \$a fi } function usage() { echo -e '\033[7mUsage:\033[0m\n dchelper [-h] [-u] [-d <repositoryDirectory>]' cat <<-EOB Options:````` -d <repositoryDirectory> designate the instances repository directory, this will be persistent, default to the script directory If you want to designate custom directory, you must use this option first. -h print this summary -i install dchelper to the system PATH, open a new terminal to use dchelper -j login to jumphost gmplts.wdf.sap.corp -r reset, in case something weird happend -u update the instances repository(in case the remote repository has fresh commits) EOB } function getRepositoryDir() { # if ! repositoryDir=$(readConfig repositoryDir 2>/dev/null); then # readConfig may return null, in this case repositoryDir is null if ! repositoryDir=$(readConfig repositoryDir) || [ -z "$repositoryDir" ]; then # repositoryDir="$scriptDir" # echo -e "\033[31;47;7mThe git repository(instances) has not been set, please sepcify the git repository(must be an absolute PATH)!\033[0m" # echo -e "\033[31;47;7mPress enter to use the default directory!\033[0m" echo -e "\033[34;47;7mPlease specify your local <Instance> repo. path(press Enter to download it locally):!\033[0m" # read repositoryDir if [ -z "$repositoryDir" ]; then repositoryDir=$scriptDir else isGitWorkTree "$repositoryDir" repositoryDir=${repositoryDir%/*} fi saveConfig repositoryDir "$repositoryDir" fi } function saveRepositoryDir() { if ! repositoryDir=$(readConfig repositoryDir) || [ -z "$repositoryDir" ]; then echo -e "\033[34;47;7mPlease specify your local <Instance> repository, path must be absolute, press enter to use the default directory!\033[0m" read repositoryDir if [ -z "$repositoryDir" ]; then repositoryDir=$scriptDir else isGitWorkTree "$repositoryDir" repositoryDir=${repositoryDir%/*} fi saveConfig repositoryDir "$repositoryDir" fi } function updateRepository() { # if ! [ -d "$repositoryDir" ]; then # mkdir -pv "$repositoryDir" # fi if ! repositoryDir=$(readConfig repositoryDir) || [ -z "$repositoryDir" ]; then echo -e "\033[31;47;7mThe repository directory has not been set, please use dchelper -d to desigate the directory first!\033[0m" exit 6 fi if ! [ -d "$repositoryDir/instances" ]; then echo -e "\033[31;47;7mPlease wait, we are cloning the repository!\033[0m" git clone --quiet --depth 1 --no-tags --shallow-submodules --remote-submodules "$repositoryURL" "$repositoryDir/instances" else cd "$repositoryDir/instances" || exit if ! git pull --quiet -n --all --force --tags --prune --jobs=5 --depth 1; then echo -e "\033[31;47;7mUpdate repository failed!\033[0m" exit 5 fi cd - >&/dev/null || exit fi } function installScript() { local scriptPath=$(getAbsolutePath dchelper) echo -e "\033[34;47;7mPlease input your sudo password to install!\033[0m" sudo ln -fnsv "$scriptPath" /usr/local/bin/dchelper >&/dev/null sudo ln -fnsv "$scriptPath" /usr/local/bin/dch >&/dev/null if [ $? -ne 0 ]; then echo -e "\033[31;47;7mThe dchelper installtion has been aborted!\033[0m" exit 5 fi # hash -r } function resetConfig() { echo -e "\033[34;47;7mPlease input your sudo password to reset configuration!\033[0m" sudo sudo rm -rf /usr/local/bin/dchelper /usr/local/bin/dch "$scriptDir"/{config,instances} # hash -r } # Initialize variables: repositoryDir & Instances repository function prerequiste() { # if [ -z "$repositoryDir" ]; then # repositoryDir="/Users/$USER/jam/instances" # read -p "Please input the instance directory in your PC:" repositoryDir # if ! [ -d "$repositoryDir" ]; then # mkdir -pv "$repositoryDir" # git clone --quiet --depth 1 --no-tags --shallow-submodules --remote-submodules REPOSITORY "$repositoryDir" # fi # fi # repositoryDir=$(getAbsolutePath "$repositoryDir") # cd "$repositoryDir" || exit # git pull --quiet -n --all --force --tags --prune --jobs=5 --depth 1 if ! [ -d "$repositoryDir/instances/.git" ]; then updateRepository fi # local str=$(findHost "$repositoryDir/instances/jam4.rb") # declare -ga arr=(${str//-/ }) # declare -a arr=(${str//-/ }) # devopsHost=${arr[0]} # dbHost=${arr[1]} } # start up execute scriptDir=$(getScriptDir) getConfigPath # echo $scriptDir # echo $config # argument parser while getopts :hud:irj opt; do case $opt in d) isGitWorkTree "$OPTARG" saveConfig repositoryDir "${OPTARG%/*}" echo -e "\033[34;47;7mThe instance repository >>$OPTARG<< is valid and saved!\033[0m" exit 0 ;; h) usage exit 0 ;; u) updateRepository echo -e "\033[34;47;7mThe repository has been updated!\033[0m" exit 0 ;; i) saveRepositoryDir if installScript; then echo -e "\033[34;47;7mThe dchelper has been successfully installed!\033[0m" exit 0 else echo -e "\033[31;47;7mThe dchelper installtion has been aborted!\033[0m" exit 5 fi ;; r) if resetConfig; then echo -e "\033[34;47;7mThe dchelper has been reset!\033[0m" exit 0 else echo -e "\033[31;47;7mThe dchelper reset aborted!\033[0m" exit 5 fi ;; j) ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=10 gmplts.wdf.sap.corp exit 0 ;; :) # option -d must have a argument, if not opt is :, OPTARG is -d if [ $OPTARG = d ]; then echo -e "\033[31;47;7;5mthe option -$OPTARG must designate the instances repository!\033[0m" else echo -e "\033[31;47;7;5mthe option -$OPTARG must have a argument!\033[0m" fi usage exit 2 ;; ?) echo -e "\033[31;47;7;5mInvalid option: -$OPTARG\033[0m" usage exit 3 ;; *) usage exit 0 ;; esac done if [ ! -L "$symbolicPath" ]; then echo -e "\033[34;47;7mThis is the first time you use dchelper, the installation is in progress!\033[0m" installScript fi getRepositoryDir # echo $repositoryDir banner prerequiste echo -en "\033[34mPlease input the DC you want to login:\033[0m " read dcName filename="$repositoryDir/instances/${dcName}.rb" if [ ! -f "$filename" ]; then echo -e "\033[31;47;7mThe correspoding $filename does not exist, check your input!\033[0m" exit 55 fi echo -en "\033[34mPlease input your RSA token to login jumphost:\033[0m " read -s rsaToken findDC # if [[ "$dcName" =~ ^jam.* ]]; then # echo "Dc name is $dcName" # else # echo "\033[31m please input correct dcName \033[0m" # exit 1 # fi # for j in $slaveInstances; do # if [ $j = "${dcName}" ]; then # checkresult='inSlaveList' # fi # done #echo "#########################################################################################" #echo devopsHost=$devopsHost dbHost=$dbHost dcName=$dcName scriptDir=$scriptDir flag=$flag #echo "#########################################################################################" #ssh -tA root@veer2 "veto(){ ssh -t root@veer3 'export PATH=\$PATH:\$HOME/.bin;declare -rx db=$dbHost s=$(findAllSalveInstances $(getSalveInstances));bash'; };export -f veto;veto" #/usr/bin/expect $scriptDir/expect.exp $rsaToken $devopsHost $dbHost "$(findAllSalveInstances $(getSalveInstances))" # echo $rsaToken '|' $devopsHost '|' $dbHost '|' $logHost '|' $appHost '|' $workerHost '|' $flag '|' "$(findAllSalveInstances $(getSalveInstances))" /usr/bin/expect $scriptDir/expect.exp $rsaToken $devopsHost $dbHost $logHost $appHost $workerHost $flag "$(findAllSalveInstances $(getSalveInstances))" # if [ -z "$devopsHost4" ];then # echo "#########################################################################################" # echo devops_pwd $devops_pwd rsaToken $rsaToken Devops_host $Devops_host devopsPassword4 $devopsPassword4 devopsHost4 $devopsHost4 # echo "#########################################################################################" # /usr/bin/expect $scriptDir/expect.exp $rsaToken $Devops_host $dbHost 2> /dev/null # else # echo "#########################################################################################" # echo "Devops_host: $Devops_host" # echo "devopsHost4: $devopsHost4" # echo "#########################################################################################" # /usr/bin/expect $scriptDir/expect.exp "not_Used_Password" $rsaToken $Devops_host $dbHost $devopsPassword4 $devopsHost4 # fi
devops.sh
#!/bin/bash # devops dbHost logHost appHost workerHost function usage() { echo -e "\033[7mUsage:\033[0m\n devops [-h]" cat <<-EOB Commands on DC: db: login into the DB slave host log: login into the log host worker: login into the worker host app: login into the app host EOB } while getopts :h opt; do case $opt in h) usage exit 0 ;; :) # option -d must have a argument, if not opt is :, OPTARG is -d echo -e "\033[31;47;7;5mthe option -$OPTARG must have a argument!\033[0m" usage exit 2 ;; ?) echo -e "\033[31;47;7;5mInvalid option: -$OPTARG\033[0m" usage exit 3 ;; *) usage exit 0 ;; esac done function db() { echo -e "\e[42mYou are logging into the DB $dbHost\e[0m" mysql -h $dbHost -u cubetree -p ct_production } function log() { echo -e "\e[42mYou are logging into the log host $logHost\e[0m" ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=10 cubetree@$logHost } function app() { echo -e "\e[42mYou are logging into the app host $appHost\e[0m" ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=10 cubetree@$appHost } function worker() { echo -e "\e[42mYou are logging into the worker host $workerHost\e[0m" ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=10 cubetree@$workerHost } function getScreenWidth() { stty size | awk '{print $2}' } function vigil() { local arr=(${s//T/ }) # echo ${arr[@]} local item local v declare -gA associative for item in ${arr[@]}; do v=(${item/-/ }) associative[${v[0]}]=${v[1]} done # seq -s~ 100 | tr -d [:digit:] printf -- '~%.0s' $(seq 1 $(getScreenWidth)) echo -e '\e[32;47;7m ^_^ Welcome to use interactive tool, You are now in central Devop host ^_^\e[0m' # seq -s~ 100 | tr -d [:digit:] printf -- '~%.0s' $(seq 1 $(getScreenWidth)) # for r in ${!associative[@]}; do # echo $r ${associative[$r]} # done PS3=$'\e[34;47;7mInput your choice >number< to access the specified DC>>\e[0m ' select name in "${!associative[@]}" "exit"; do # echo 'name='$name case $name in "db") db break ;; "log") echo -e '\e[31;47;7mNot Implemented!! Choose Again!\e[0m' ;; "veto") ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=10 -t root@veer2 "db(){ echo -e \"\e[42mYou are logging into the DB ${v[1]}\e[0m\"; mysql -h ${v[1]} -u cubetree -p ct_production; };export -f db;bash -il" break ;; jam*) v=${associative["$name"]} v=(${v//-/ }) ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=10 -t devops@${v[0]} "db(){ echo -e \"\e[42mYou are logging into the DB ${v[1]}\e[0m\"; mysql -h ${v[1]} -u cubetree -p ct_production; };log(){ echo -e \"\e[42mYou are logging into the log host ${v[2]}\e[0m\"; ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=10 cubetree@${v[2]}; };app(){ echo -e \"\e[42mYou are logging into the app host ${v[3]}\e[0m\"; ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=10 cubetree@${v[3]}; };worker(){ echo -e \"\e[42mYou are logging into the worker host ${v[4]}\e[0m\"; ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=10 cubetree@${v[4]}; };export -f db log app worker;bash -il" break ;; "exit") echo -e '\e[33;7mexit the tool, you can type dch in shell to call me again.\e[0m' break ;; *) echo -e '\e[33;7mWrong Number, You have to type a number!!\e[0m' ;; esac done } if [ "$flag" = true ]; then vigil else ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=10 -t devops@$devopsHost "db(){ echo -e \"\e[42mYou are logging into the DB $dbHost\e[0m\"; mysql -h $dbHost -u cubetree -p ct_production; };log(){ echo -e \"\e[42mYou are logging into the log host $logHost\e[0m\"; ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=10 cubetree@$logHost; };app(){ echo -e \"\e[42mYou are logging into the app host $appHost\e[0m\"; ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=10 cubetree@$appHost; };worker(){ echo -e \"\e[42mYou are logging into the worker host $workerHost\e[0m\"; ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=10 cubetree@$workerHost; };export -f db log app worker;bash -il" fi
expect.exp
#!/usr/bin/expect -f set timeout 20 set rsaToken [lindex $argv 0] set devopsHost [lindex $argv 1] set dbHost [lindex $argv 2] set logHost [lindex $argv 3] set appHost [lindex $argv 4] set workerHost [lindex $argv 5] set flag [lindex $argv 6] set s [lindex $argv 7] log_user 0 send_user "\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" send_user "\033\[34;47;7m^_^ Be patient, it will take a few seconds to log in target devops host .... ^_^\033\[0m\n" send_user "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" send_user "\033\[34;47;7mPlease input devops host password once the 'Password' is prompted ^_^\033\[0m\n" # sample: spawn ssh -tA gmplts.wdf.sap.corp "veto(){ ssh -t devops@$devopsHost ''; };export -f veto;veto" # sample: spawn ssh -tA gmplts.wdf.sap.corp "veto(){ ssh -t devops@$devopsHost 'db(){ mysql -h $dbHost -u cubetree -p ct_production; };export -f db;bash'; };export -f veto;veto" if { "$flag" == "true" } { spawn ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=10 -tA gmplts.wdf.sap.corp "veto(){ ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=10 -t devops@$devopsHost 'db(){ mysql -h $dbHost -u cubetree -p ct_production; };log(){ ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=10 cubetree@$logHost; };app(){ ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=10 cubetree@$appHost; };worker(){ ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=10 cubetree@$workerHost; };export -f db log app worker;export PATH=\$PATH:\$HOME/.bin;declare -x devopsHost=$devopsHost dbHost=$dbHost logHost=$logHost appHost=$appHost workerHost=$workerHost s=$s flag=$flag;bash -il'; };export -f veto;veto" } elseif { "$flag" == "false" } { spawn ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=10 -tA gmplts.wdf.sap.corp "veto(){ ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=10 -t devops@10.4.70.39 'db(){ mysql -h $dbHost -u cubetree -p ct_production; };log(){ ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=10 cubetree@$logHost; };app(){ ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=10 cubetree@$appHost; };worker(){ ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=10 cubetree@$workerHost; };export -f db log app worker;export PATH=\$PATH:\$HOME/.bin;declare -x devopsHost=$devopsHost dbHost=$dbHost logHost=$logHost appHost=$appHost workerHost=$workerHost s=$s flag=$flag;devops;declare -x flag=true;bash -il'; };export -f veto;veto" #spawn ssh -tA gmplts.wdf.sap.corp ssh -t devops@10.4.70.39 "veto(){ ssh -t devops@$devopsHost 'db(){ mysql -h $dbHost -u cubetree -p ct_production; };export -f db;bash'; };export -f veto;veto" #spawn ssh -tA gmplts.wdf.sap.corp ssh -t devops@10.4.70.39 ssh -t devops@$devopsHost "db(){ mysql -h $dbHost -u cubetree -p ct_production; };export -f db;bash" } else { spawn ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=10 -tA gmplts.wdf.sap.corp "veto(){ ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=10 -t devops@$devopsHost 'db(){ mysql -h $dbHost -u cubetree -p ct_production; };log(){ ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=10 cubetree@$logHost; };app(){ ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=10 cubetree@$appHost; };worker(){ ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=10 cubetree@$workerHost; };export -f db log app worker;bash -il'; };export -f veto;veto" # spawn ssh -tA gmplts.wdf.sap.corp "veto(){ ssh -t devops@$devopsHost 'dbintegration(){ mysql -h 10.181.40.190 -u cubetree -p ct_production; };dbstage(){ mysql -h $dbHost -u cubetree -p ct_production; };export -f dbstage dbintegration;bash'; };export -f veto;veto" } #spawn ssh -tA root@veer2 "veto(){ ssh -t root@veer3 'export PATH=\$PATH:\$HOME/.bin;declare -rx db=$db s=$s;bash'; };export -f veto;veto" #spawn ssh -tA gmplts.wdf.sap.corp "veto(){ ssh -t devops@$devopsHost 'db(){ mysql -h $dbHost -u cubetree -p ct_production; };export -f db;export PATH=\$PATH:\$HOME/.bin;declare -x destinationDC=$destinationDC destinationDB=$destinationDB;bash'; };export -f veto;veto" #expect "Password:" #send "$rsaToken\r" # expect { "yes/no" { send "yes\n"; exp_continue } "Password" { send "$rsaToken\n" } } interact
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
2021-09-28 apt_preferences
2020-09-28 iptables
2020-09-28 生产中变更VPN密码,并发送邮件通知shell脚本
2020-09-28 Linux 字节序
2020-09-28 shell getopts
2020-09-28 放行WAF回源IP段