├── tuning ├── java │ └── bin │ │ ├── lib │ │ ├── jtop.jar │ │ ├── vjmap.jar │ │ ├── vjmxcli.jar │ │ ├── sjk-0.10.1.jar │ │ ├── sjk-0.4.2.jar │ │ ├── MonBuffers.class │ │ ├── housemd_0.2.6.min.jar │ │ ├── greys-1.7.6.4 │ │ │ ├── greys-agent.jar │ │ │ └── greys-core.jar │ │ ├── jvm.list │ │ ├── jvm.dsc │ │ └── MonBuffers.java │ │ ├── sjk │ │ ├── housemd │ │ ├── jargrep │ │ ├── findcycle │ │ ├── vjmxcli │ │ ├── vjmap │ │ ├── jvm │ │ ├── show-duplicate-java-classes │ │ ├── greys │ │ ├── find-in-jars │ │ ├── vjdump │ │ └── show-busy-java-threads ├── bin │ ├── update │ ├── xpf │ ├── change_git_origin_remote │ ├── send │ ├── tcp-connection-state-counter │ ├── ap │ ├── c │ ├── echo-args │ ├── a2l │ ├── show-cpu-and-memory │ ├── hex │ ├── rp │ ├── redis │ ├── check-vm │ ├── swtrunk │ ├── colines │ ├── cp-svn-url │ ├── xpl │ ├── console-text-color-themes │ ├── swap │ ├── monitor-host │ ├── svn-merge-stop-on-copy │ └── parseOpts ├── docs │ ├── console-colorful-text.png │ ├── vcs.md │ ├── shell.md │ └── java.md ├── Makefile ├── opscripts ├── opscripts-common.sh ├── tpl │ └── run-cmd-tpl.sh ├── test-cases │ └── parseOpts-test.sh ├── README.md └── LICENSE ├── harden ├── cleanup │ └── clear-log.sh └── harden │ └── basic.sh ├── ops ├── 批量创建用户并赋予 sudo 权限.sh └── 检测 Apache 与 Nginx 访问峰值.sh ├── .gitignore ├── misc └── git │ └── clean_gitlab_pipeline.py ├── self-installer.sh └── README.md /tuning/java/bin/lib/jtop.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wx-chevalier/ms-devops-scripts/master/tuning/java/bin/lib/jtop.jar -------------------------------------------------------------------------------- /tuning/java/bin/lib/vjmap.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wx-chevalier/ms-devops-scripts/master/tuning/java/bin/lib/vjmap.jar -------------------------------------------------------------------------------- /tuning/bin/update: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "update opscripts ..." 4 | cd $OPSCRIPTS_DIR && git pull 5 | 6 | echo "update finished!" -------------------------------------------------------------------------------- /tuning/java/bin/lib/vjmxcli.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wx-chevalier/ms-devops-scripts/master/tuning/java/bin/lib/vjmxcli.jar -------------------------------------------------------------------------------- /tuning/java/bin/lib/sjk-0.10.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wx-chevalier/ms-devops-scripts/master/tuning/java/bin/lib/sjk-0.10.1.jar -------------------------------------------------------------------------------- /tuning/java/bin/lib/sjk-0.4.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wx-chevalier/ms-devops-scripts/master/tuning/java/bin/lib/sjk-0.4.2.jar -------------------------------------------------------------------------------- /tuning/docs/console-colorful-text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wx-chevalier/ms-devops-scripts/master/tuning/docs/console-colorful-text.png -------------------------------------------------------------------------------- /tuning/java/bin/lib/MonBuffers.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wx-chevalier/ms-devops-scripts/master/tuning/java/bin/lib/MonBuffers.class -------------------------------------------------------------------------------- /tuning/java/bin/lib/housemd_0.2.6.min.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wx-chevalier/ms-devops-scripts/master/tuning/java/bin/lib/housemd_0.2.6.min.jar -------------------------------------------------------------------------------- /tuning/java/bin/lib/greys-1.7.6.4/greys-agent.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wx-chevalier/ms-devops-scripts/master/tuning/java/bin/lib/greys-1.7.6.4/greys-agent.jar -------------------------------------------------------------------------------- /tuning/java/bin/lib/greys-1.7.6.4/greys-core.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wx-chevalier/ms-devops-scripts/master/tuning/java/bin/lib/greys-1.7.6.4/greys-core.jar -------------------------------------------------------------------------------- /tuning/bin/xpf: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # @Function 3 | ## Open file in file explorer. 4 | # same as xpl --selected [FILE] 5 | # 6 | # @Usage 7 | # $ ./xpf file 8 | # 9 | # @author Jerry Lee 10 | BASE=`dirname $0` 11 | . $BASE/xpl "$@" 12 | -------------------------------------------------------------------------------- /tuning/bin/change_git_origin_remote: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # @Function 3 | ## change origin remote of the git repository 4 | # 5 | # @Usage 6 | # $ ./change_git_origin_remote [new_origin_remote_url] 7 | # 8 | # @author Bryant Hang 9 | 10 | git remote rm origin 11 | git remote add origin $1 12 | 13 | git fetch 14 | 15 | git branch --set-upstream-to=origin/master master 16 | -------------------------------------------------------------------------------- /tuning/bin/send: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ## sending file by nc 3 | port=8888 4 | if [ $# -eq 0 ];then 5 | echo 'Usage : send file [port](default port is 8888)' 6 | exit 1; 7 | fi 8 | file=$1; 9 | if [ $# -gt 1 ];then 10 | port=$2; 11 | fi 12 | ip=`ifconfig | grep 'inet ' | grep -v '127.0.0.1' | head -n1 | awk '{print $2}'` 13 | echo "sending file '$file' on $ip $port " 14 | nc -l $port < $file -------------------------------------------------------------------------------- /tuning/bin/tcp-connection-state-counter: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # @Function 3 | ## show count of tcp connection stat. 4 | # 5 | # @Usage 6 | # $ ./tcp-connection-state-counter.sh 7 | # 8 | # @author Jerry Lee 9 | # @author @sunuslee 10 | 11 | uname | grep Darwin -q && option_for_mac="-ptcp" 12 | 13 | netstat -tna $option_for_mac | awk 'NR > 2 { 14 | s[$NF]++ 15 | } 16 | 17 | END { 18 | for(v in s) { 19 | printf "%-11s %s\n", v, s[v] 20 | } 21 | }' | sort -nr -k2,2 22 | -------------------------------------------------------------------------------- /tuning/java/bin/sjk: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ## start sjk 3 | 4 | echo "Site: https://github.com/aragozin/jvm-tools" 5 | 6 | base_dir=$(dirname "$(echo "$0" | sed -e '')") 7 | if [ ! "$JAVA_HOME" = "" ] ;then 8 | java_home=$JAVA_HOME 9 | fi 10 | 11 | if [ ! -f "$java_home/lib/tools.jar" ] && [ "$(uname)" != "Darwin" ];then 12 | echo "$java_home/lib/tools.jar not found!" 13 | exit 1; 14 | fi 15 | 16 | java -Xbootclasspath/a:$java_home/lib/tools.jar -jar $base_dir/lib/sjk-0.10.1.jar $@ 17 | -------------------------------------------------------------------------------- /tuning/bin/ap: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # @Function 3 | ## convert to Absolute Path. 4 | # 5 | # @Usage 6 | # # print Absolute Path of current directory. 7 | # $ ./ap 8 | # # print Absolute Path of arguments. 9 | # $ ./ap a.txt ../dir1/b.txt 10 | # 11 | # @author Jerry Lee 12 | 13 | [ $# -eq 0 ] && files=(.) || files=("$@") 14 | 15 | for f in "${files[@]}" ; do 16 | ! [ -e "$f" ] && { 17 | echo "$f does not exists!" 18 | continue 19 | } 20 | readlink -f "$f" 21 | done 22 | -------------------------------------------------------------------------------- /harden/cleanup/clear-log.sh: -------------------------------------------------------------------------------- 1 | # Clear nginx logs. 2 | # @usage delnginxlogs 3 | function delnginxlogs() { 4 | echo "--------------- ⏲ Clearing logs... ---------------" 5 | 6 | # Clear logs. 7 | for i in /var/log/nginx/*; do cat /dev/null > $i; done 8 | 9 | echo "--------------- ⏲ Deleting .gz log files... ---------------" 10 | 11 | # Delete .gz files. 12 | find /var/log/nginx -type f -regex ".*\.gz$" -delete 13 | 14 | echo "--------------- 💯 DONE: NGINX logs cleared ... ---------------" 15 | } -------------------------------------------------------------------------------- /tuning/Makefile: -------------------------------------------------------------------------------- 1 | prefix=/usr/local 2 | 3 | all: 4 | @echo "usage: make install" 5 | @echo " make uninstall" 6 | 7 | install: 8 | @mkdir -p $(prefix)/bin/ 9 | @echo '#!/bin/bash' > $(prefix)/bin/opscripts 10 | @echo '##$(shell pwd)' >> $(prefix)/bin/opscripts 11 | @echo 'exec "$(shell pwd)/opscripts" "$$@"' >> $(prefix)/bin/opscripts 12 | @chmod 755 $(prefix)/bin/opscripts 13 | @chmod 755 opscripts 14 | @echo 'install finished! type "opscripts" to show usages.' 15 | uninstall: 16 | @rm -f $(prefix)/bin/opscripts -------------------------------------------------------------------------------- /ops/批量创建用户并赋予 sudo 权限.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | username=yourname 4 | password=yourpassword 5 | 6 | if [ -n $username ] 7 | then 8 | groupadd $username -g 10036 9 | useradd -m $username -g $username -u 10036 10 | echo "$password" | passwd --stdin $username 11 | echo "user $username group $username is changed!" 12 | else 13 | echo "use $username is fail" 14 | fi 15 | 16 | ####add sudo power #### 17 | 18 | echo "$username ALL = (root) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/$username 19 | sudo chmod 0440 /etc/sudoers.d/$username -------------------------------------------------------------------------------- /tuning/bin/c: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # @Function 3 | ## Run command and put output to system clipper. 4 | # 5 | # @Usage 6 | # $ c echo "hello world!" 7 | # $ echo "hello world!" | c 8 | # 9 | # @author Jerry Lee 10 | copy() { 11 | case "`uname`" in 12 | Darwin*) 13 | pbcopy ;; 14 | CYGWIN*) 15 | clip ;; 16 | MINGW*) 17 | clip ;; 18 | *) 19 | xsel -b ;; 20 | esac 21 | } 22 | 23 | teeAndCopy() { 24 | tee >(content="$(cat)"; echo -n "$content" | copy) 25 | } 26 | 27 | if [ $# -eq 0 ]; then 28 | teeAndCopy 29 | else 30 | "$@" | teeAndCopy 31 | fi 32 | -------------------------------------------------------------------------------- /tuning/bin/echo-args: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ## echo args 3 | 4 | redEcho() { 5 | if [ -c /dev/stdout ] ; then 6 | # if stdout is console, turn on color output. 7 | echo -ne "\033[1;31m" 8 | echo -n "$@" 9 | echo -ne "\033[0m" 10 | else 11 | echo -n "$@" 12 | fi 13 | } 14 | 15 | echoArg() { 16 | local index=$1 17 | local count=$2 18 | local value=$3 19 | 20 | echo -n "$index/$count: " 21 | redEcho "[" 22 | echo -n "$value" 23 | redEcho "]" 24 | echo 25 | } 26 | 27 | 28 | echoArg 0 $# "$0" 29 | idx=1 30 | for a ; do 31 | echoArg $((idx++)) $# "$a" 32 | done 33 | -------------------------------------------------------------------------------- /tuning/java/bin/housemd: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ## start housemd debugger 3 | 4 | base_dir=$(dirname "$(echo "$0" | sed -e '')") 5 | if [ $# -eq 0 ];then 6 | echo "Usage : housemd pid [java_home]" 7 | echo "Site: https://github.com/CSUG/HouseMD/wiki/UserGuideCN" 8 | exit 1; 9 | fi 10 | if [ ! "$JAVA_HOME" = "" ] ;then 11 | java_home=$JAVA_HOME 12 | fi 13 | if [ $# -gt 1 ];then 14 | java_home=$2; 15 | fi 16 | if [ ! -f "$java_home/lib/tools.jar" ] && [ "$(uname)" != "Darwin" ];then 17 | echo "$java_home/lib/tools.jar not found!" 18 | exit 1; 19 | fi 20 | 21 | java -Xbootclasspath/a:$java_home/lib/tools.jar -jar $base_dir/lib/housemd_0.2.6.min.jar $1 -------------------------------------------------------------------------------- /tuning/bin/a2l: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # @Function 3 | ## echo each arguments on one line colorfully. 4 | # 5 | # @Usage 6 | # $ ./a2l arg1 arg2 7 | # $ ./a2l *.txt 8 | # 9 | # @author Jerry Lee 10 | 11 | 12 | colorEcho() { 13 | local color="$1" 14 | shift 15 | if [ -c /dev/stdout ] ; then 16 | # if stdout is console, turn on color output. 17 | echo -ne "\033[1;${color}m" 18 | echo -n "$@" 19 | echo -e "\033[0m" 20 | else 21 | echo "$@" 22 | fi 23 | } 24 | 25 | readonly ECHO_COLORS=(37 31 32 34 33 35 56) 26 | COUNT=0 27 | 28 | for a in "$@"; do 29 | colorEcho "${ECHO_COLORS[$((COUNT++ % ${#ECHO_COLORS[@]}))]}" "$a" 30 | done 31 | -------------------------------------------------------------------------------- /tuning/java/bin/jargrep: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ## grep text in jars 3 | 4 | if [ $# -lt 2 ];then 5 | echo 'Usage : jargrep text ' 6 | exit 1; 7 | fi 8 | 9 | LOOK_FOR=$1 10 | LOOK_FOR=`echo ${LOOK_FOR//\./\/}` 11 | while true; do 12 | folder=$2 13 | if [ "$folder" = "" ];then 14 | break; 15 | fi 16 | echo "finding '$LOOK_FOR' in $folder ..." 17 | if [ -d "$folder" ]; then 18 | for i in `find $2 -name "*jar"` 19 | do 20 | unzip -p $i | grep "$LOOK_FOR" > /dev/null 21 | if [ $? = 0 ] then 22 | echo "==> Found \"$LOOK_FOR\" in $i" 23 | fi 24 | done 25 | fi 26 | if [ -f "$folder" ]; then 27 | zipgrep "$LOOK_FOR" "$folder" 28 | fi 29 | shift; 30 | done; -------------------------------------------------------------------------------- /tuning/java/bin/findcycle: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ## find cycle in maven depnedency tree 3 | 4 | if [ $# -gt 0 ];then 5 | sourcepath=$1 6 | else 7 | sourcepath=`pwd` 8 | fi 9 | if [ ! -f "$sourcepath/pom.xml" ]; then 10 | echo "$sourcepath is not a vaild maven project!" 11 | echo 'Usage : findcycle [path]' 12 | exit 1; 13 | fi 14 | mvn=`which mvn` 15 | if [ "$mvn" = "" ];then 16 | echo "counld not found mvn in PATH,exit!" 17 | exit 1; 18 | fi 19 | 20 | cd $sourcepath 21 | echo "scan cycle dependency in $sourcepath ..." 22 | mvn dependency:tree -Dverbose | awk -F'- ' '{if(index($2,"maven-dependency-plugin")>0){indent=0;}else{indent=length($1);}stack[indent]=$2;if(index($0,"for cycle")>0){print "****found cycle****";for(i=0;i<=indent;i++){if(stack[i]!=null){print "->"stack[i]}}}}' 23 | echo "scan finished!" 24 | -------------------------------------------------------------------------------- /tuning/bin/show-cpu-and-memory: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # @Function 3 | ## Show total and every process's memory and cpu usage 4 | # 5 | # @Usage 6 | # $ ./show-cpu-and-memory.sh 7 | # 8 | # @author Bryant Hang 9 | 10 | readonly cur_date="`date +%Y%m%d`" 11 | 12 | readonly total_mem="`free -m | grep 'Mem'`" 13 | readonly total_cpu="`top -n 1 | grep 'Cpu'`" 14 | 15 | echo '**********'$cur_date'**********' 16 | echo 17 | echo "total memory: $total_mem" 18 | echo "total cpu: $total_cpu" 19 | echo 20 | 21 | for pid in `ps -ef | awk 'NR > 1 {print $2}'` ; do 22 | # not pid 23 | if [[ $pid == *[!0-9]* ]]; then 24 | continue 25 | fi 26 | 27 | mem=`cat /proc/$pid/status 2> /dev/null | grep VmRSS | awk '{print $2 $3}'` 28 | cpu=`top -n 1 -b | awk -v "pid=${pid}" '$1==pid {print $9}'` 29 | 30 | echo "pid: $pid, memory: $mem, cpu:$cpu%" 31 | done 32 | -------------------------------------------------------------------------------- /tuning/bin/hex: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ## hexadecimal conversion 3 | 4 | if [ $# = 0 ]; then 5 | echo "Usage :hex [0x]number[b]" 6 | echo "number could be hexadecimal(0x),binary(b),or decimal(default)" 7 | exit 0; 8 | fi 9 | input=$1 10 | echo $input | grep -q "^0x" 11 | if [ $? = 0 ];then 12 | hex_number=$input 13 | dec_number=$(($input)) 14 | binary_number=`echo "obase=2;$dec_number"|bc` 15 | fi 16 | echo $input | grep -q "b$" 17 | if [ $? = 0 ]; then 18 | binary_number=`echo $input |cut -c1-$((${#input}-1))` 19 | dec_number=$((2#$binary_number)) 20 | hex_number=`printf "%x" $dec_number` 21 | fi 22 | 23 | if [ "$dec_number" = "" ]; then 24 | dec_number=$input 25 | hex_number=`printf "%x" $dec_number` 26 | binary_number=`echo "obase=2;$dec_number"|bc` 27 | fi 28 | echo "2 : "$binary_number"b" 29 | echo "10: "$dec_number 30 | echo "16: "$hex_number -------------------------------------------------------------------------------- /tuning/java/bin/vjmxcli: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo '==========Thanks to https://github.com/vipshop/vjtools==========' 4 | 5 | PRGDIR=`dirname "$0"` 6 | BASEDIR=`cd "$PRGDIR/lib" >/dev/null; pwd` 7 | 8 | if [ -z "$JAVA_HOME" ] ; then 9 | JAVA_HOME=`readlink -f \`which java 2>/dev/null\` 2>/dev/null | \ 10 | sed 's/\/bin\/java//'` 11 | fi 12 | 13 | TOOLSJAR="$JAVA_HOME/lib/tools.jar" 14 | 15 | if [ ! -f "$TOOLSJAR" ] ; then 16 | echo "$JAVA_HOME seems to be no JDK!" >&2 17 | exit 1 18 | fi 19 | 20 | JAVA_VERSION=$("$JAVA_HOME"/bin/java -version 2>&1 | awk -F '"' '/version/ {print $2}') 21 | 22 | JAVA_OPTS="-Xms96m -Xmx96m -Xmn64m -Xss256k -XX:ReservedCodeCacheSize=2496k -XX:AutoBoxCacheMax=20000 -XX:+UseSerialGC -Djava.compiler=NONE -Xverify:none" 23 | 24 | "$JAVA_HOME"/bin/java $JAVA_OPTS -cp "$BASEDIR/vjmxcli.jar:$TOOLSJAR" \com.vip.vjtools.jmx.Client $* 25 | -------------------------------------------------------------------------------- /tuning/opscripts: -------------------------------------------------------------------------------- 1 | 2 | #!/bin/bash 3 | 4 | export OPSCRIPTS_DIR=$(dirname $0) 5 | 6 | # load common lib functions 7 | source $OPSCRIPTS_DIR/opscripts-common.sh 8 | 9 | if [ $# = 0 ];then 10 | print_column 'Usage ' 11 | print_column " opscripts list\t: show all commands \nopscripts update\t: update opscripts \nopscripts command\t: execute a command\nopscripts uninstall\t: uninstall opscripts" 12 | exit 13 | fi 14 | 15 | if [ "$1" = "list" ];then 16 | list_command "$@" 17 | fi 18 | 19 | bin_dir=$OPSCRIPTS_DIR/bin/ 20 | java_bin_dir=$OPSCRIPTS_DIR/java/bin/ 21 | command_file=$1;shift 22 | command=`find $bin_dir -maxdepth 1 -name $command_file ` 23 | 24 | if [ ! -f "$command" ]; then 25 | command=`find $java_bin_dir -maxdepth 1 -name $command_file ` 26 | if [ ! -f "$command" ]; then 27 | echo "$command_file command not found!" 28 | exit 1; 29 | fi 30 | fi 31 | 32 | exec "$command" "$@" -------------------------------------------------------------------------------- /tuning/bin/rp: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # @Function 3 | ## convert to Relative Path. 4 | # 5 | # @Usage 6 | # # if 1 argument, print relative path to current dir. 7 | # $ ./rp /etc/apache2/httpd.conf 8 | # # if more than 1 argument, print relative path to last argument. 9 | # $ ./rp a.txt ../b.txt /etc/passwd /etc/apache2 10 | # 11 | # @author Jerry Lee 12 | 13 | [ $# -eq 0 ] && { 14 | echo "ERROR: NO argument!" 15 | exit 1 16 | } 17 | 18 | [ $# -eq 1 ] && { 19 | relativeTo=. 20 | files=("$@") 21 | } || { 22 | argv=("$@") 23 | argc=$# 24 | 25 | # Get last argument 26 | relativeTo="${argv[$((argc - 1))]}" 27 | files=( "${argv[@]:0:$((argc - 1))}" ) 28 | } 29 | 30 | [ -f "$relativeTo" ] && relativeTo="$(dirname "$relativeTo")" 31 | 32 | for f in "${files[@]}" ; do 33 | ! [ -e $f ] && { 34 | echo "$f does not exists!" 35 | continue 36 | } 37 | realpath "$f" --relative-to="$relativeTo" 38 | done 39 | -------------------------------------------------------------------------------- /tuning/bin/redis: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ## execute redis command 3 | if [ $# -lt 2 ];then 4 | echo 'Usage : redis ip1[:port1][,ip2[:port2]] [port] "command"' 5 | exit; 6 | fi 7 | ip=$1 8 | shift; 9 | if [ $1 -gt 0 2>/dev/null ];then 10 | port=$1 11 | uniq_port=1; 12 | shift; 13 | fi 14 | 15 | array=(${ip//,/ }) ; 16 | redis_cli=`which redis-cli` 17 | if [ "$redis_cli" = "" ];then 18 | redis_cli=`locate bin/redis-cli | head -n 1` 19 | if [ "$redis_cli" = "" ];then 20 | echo 'no redis-cli found!' 21 | exit; 22 | else 23 | echo "cannot found redis-cli in PATH,use $redis_cli" 24 | fi 25 | fi 26 | for i in "${!array[@]}"; do 27 | temp="${array[i]}"; 28 | arr=(${temp//:/ }); 29 | if [ "$port" = "" ];then 30 | port=${arr[1]} 31 | if [ "$port" = "" ];then 32 | echo "error param" 33 | exit; 34 | fi 35 | fi 36 | echo "${arr[0]}:${port}"; 37 | echo $@ 38 | ${redis_cli} -h "${arr[0]}" -p "${port}" "$@" 39 | if [ "$uniq_port" = "" ];then 40 | port="" 41 | fi 42 | done 43 | -------------------------------------------------------------------------------- /tuning/java/bin/vjmap: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ## use vjmap to view heap usage in generation 3 | 4 | echo '==========Thanks to https://github.com/vipshop/vjtools==========' 5 | 6 | if [ -z "$JAVA_HOME" ]; then 7 | echo "JAVA_HOME env is not set, try to find it out" 8 | 9 | JAVA_PATH=`which java 2>/dev/null` 10 | if [ "x$JAVA_PATH" != "x" ]; then 11 | JAVA_PATH=`dirname $JAVA_PATH 2>/dev/null` 12 | JAVA_HOME=`dirname $JAVA_PATH 2>/dev/null` 13 | fi 14 | fi 15 | 16 | SA_JDI_PATH=$JAVA_HOME/lib/sa-jdi.jar 17 | JAVA_VERSION=$(java -version 2>&1 | awk -F '"' '/version/ {print $2}') 18 | 19 | echo -e "\033[31mWARNING!! STW(Stop-The-World) will be performed on your Java process, if this is NOT wanted, type 'Ctrl+C' to exist. \033[0m" 20 | echo "using JDK $JAVA_VERSION" 21 | 22 | PRGDIR=`dirname "$0"` 23 | BASEDIR=`cd "$PRGDIR/lib" >/dev/null; pwd` 24 | 25 | if [ -f ${SA_JDI_PATH} ]; then 26 | java -XX:AutoBoxCacheMax=20000 -classpath $BASEDIR/vjmap.jar:$SA_JDI_PATH com.vip.vjtools.vjmap.VJMap $* 27 | else 28 | echo "JAVA_HOME/lib/sa-jdi.jar is not exist, please set your JAVA_HOME env"; 29 | fi 30 | -------------------------------------------------------------------------------- /tuning/bin/check-vm: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | ## check if a linux system running on a virtual machine (openvz/xen pv/uml VmWare) 4 | 5 | import sys, os 6 | 7 | def main(): 8 | if os.getuid() != 0: 9 | print "must be run as root" 10 | sys.exit(0) 11 | 12 | # check OpenVZ/Virtuozzo 13 | if os.path.exists("/proc/vz"): 14 | if not os.path.exists("/proc/bc"): 15 | print "openvz container" 16 | else: 17 | print "openvz node" 18 | 19 | # check Xen 20 | if os.path.exists("/proc/xen/capabilities"): 21 | if (os.path.getsize("/proc/xen/capabilities") > 0): 22 | print "xen dom0" 23 | else: 24 | print "xen domU" 25 | 26 | # check User Mode Linux (UML) 27 | f = open("/proc/cpuinfo", "r"); t = f.read(); f.close() 28 | if (t.find("UML") > 0): 29 | print "uml" 30 | 31 | # check VMWare 32 | f = open("/proc/scsi/scsi", "r"); t = f.read(); f.close() 33 | if (t.find("VMware") > 0): 34 | print "VMware" 35 | 36 | if __name__=="__main__": 37 | main() 38 | -------------------------------------------------------------------------------- /tuning/bin/swtrunk: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # @Function 3 | ## switch svn work directory to trunk. 4 | # 5 | # @Usage 6 | # $ ./swtrunk.sh [...] 7 | # 8 | # @author Jerry Lee 9 | 10 | colorEcho() { 11 | local color=$1 12 | shift 13 | if [ -c /dev/stdout ] ; then 14 | # if stdout is console, turn on color output. 15 | echo -ne "\033[1;${color}m" 16 | echo -n "$@" 17 | echo -e "\033[0m" 18 | else 19 | echo "$@" 20 | fi 21 | } 22 | 23 | redEcho() { 24 | colorEcho 31 "$@" 25 | } 26 | 27 | greenEcho() { 28 | colorEcho 32 "$@" 29 | } 30 | 31 | [ $# -eq 0 ] && dirs=(.) || dirs=("$@") 32 | 33 | for d in "${dirs[@]}" ; do 34 | [ ! -d ${d}/.svn ] && { 35 | redEcho "directory $d is not a svn work directory, ignore directory $d !" 36 | continue 37 | } 38 | ( 39 | cd "$d" && 40 | branches=`svn info | grep '^URL' | awk '{print $2}'` && 41 | trunk=`echo $branches | awk -F'/branches/' '{print $1}'`/trunk && 42 | 43 | svn sw "$trunk" && 44 | greenEcho "svn work directory $d switch from ${branches} to ${trunk} ." || 45 | redEcho "fail to switch $d to trunk!" 46 | ) 47 | done 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # ---> Python 2 | # Byte-compiled / optimized / DLL files 3 | __pycache__/ 4 | *.py[cod] 5 | *$py.class 6 | 7 | .pytest_cache/ 8 | # C extensions 9 | *.so 10 | 11 | # Distribution / packaging 12 | .Python 13 | env/ 14 | build/ 15 | develop-eggs/ 16 | dist/ 17 | downloads/ 18 | eggs/ 19 | .eggs/ 20 | lib64/ 21 | parts/ 22 | sdist/ 23 | var/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | .idea/ 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .coverage 43 | .coverage.* 44 | .cache 45 | nosetests.xml 46 | coverage.xml 47 | *,cover 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | 56 | # Sphinx documentation 57 | docs/_build/ 58 | 59 | # PyBuilder 60 | target/ 61 | 62 | .venv 63 | .vscode 64 | 65 | .index 66 | .DS_Store 67 | .resources 68 | .mypy_cache 69 | cscan-index 70 | !dist/requirements.txt 71 | 72 | .cscan 73 | .dist 74 | .docker 75 | 76 | .private -------------------------------------------------------------------------------- /tuning/bin/colines: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Function 4 | ## cat lines colorfully. colines means COLorful LINES. 5 | # 6 | # @Usage 7 | # $ echo -n 'Hello\nWorld' | colines 8 | # $ colines /path/to/file1 9 | # $ colines /path/to/file1 /path/to/file2 10 | 11 | 12 | __author__ = 'Jerry Lee' 13 | 14 | import sys 15 | 16 | ECHO_COLORS = (37, 31, 32, 34, 33, 35, 56) 17 | idx = 0 18 | 19 | 20 | def color_print(*args): 21 | _line = " ".join(args) 22 | global idx 23 | idx += 1 24 | color = ECHO_COLORS[idx % len(ECHO_COLORS)] 25 | if sys.stdout.isatty(): 26 | print("""\033[1;%sm%s\033[0m""" % (color, _line)) 27 | else: 28 | print(_line) 29 | 30 | 31 | if __name__ == '__main__': 32 | if len(sys.argv) > 1: 33 | for arg in sys.argv[1:]: 34 | if len(sys.argv) > 2: 35 | print('=' * 80) 36 | print(arg) 37 | print('=' * 80) 38 | for line in open(arg).readlines(): 39 | color_print(line.rstrip('\r\n')) 40 | else: 41 | # Read from std input 42 | while True: 43 | line = sys.stdin.readline() 44 | if not line: 45 | break 46 | color_print(line.rstrip('\r\n')) -------------------------------------------------------------------------------- /tuning/bin/cp-svn-url: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # @Function 3 | ## copy the svn remote url of current svn directory. 4 | # 5 | # @Usage 6 | # $ ./cp-svn-url.sh 7 | # $ ./cp-svn-url.sh /path/to/svn/work/dir 8 | # 9 | # @author ivanzhangwb 10 | readonly PROG=`basename $0` 11 | 12 | usage() { 13 | cat <&2 39 | exit 1 40 | fi 41 | 42 | copy() { 43 | local name=$(uname | tr A-Z a-z) 44 | 45 | case "${name}" in 46 | darwin*) 47 | pbcopy ;; 48 | cygwin*) 49 | clip ;; 50 | mingw*) 51 | clip ;; 52 | *) 53 | xsel -b ;; 54 | esac 55 | } 56 | 57 | echo -n "${url}" | copy && echo "${url} copied!" 58 | -------------------------------------------------------------------------------- /tuning/opscripts-common.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | print_column (){ 4 | echo -e $1 |awk -F'\t' '{printf "%-15s%s\n",$1,$2}' 5 | } 6 | 7 | print_title (){ 8 | length=`echo "$1" |wc -c` 9 | prefix_count=$(((30-length)/2)) 10 | for i in `seq 0 $prefix_count` ;do 11 | echo -n '=' 12 | done 13 | echo -n " $1 " 14 | postfix_count=$((length % 2 != 0 ? prefix_count+1: prefix_count)) 15 | for i in `seq 0 $postfix_count` ;do 16 | echo -n '=' 17 | done 18 | printf '\r\n' 19 | } 20 | 21 | find_command(){ 22 | commands=`ls -l $1/bin |grep -v '^d' |awk '{print $9}'` 23 | if [ "$commands" = "" ]; then 24 | return 25 | fi 26 | 27 | for file in $commands ;do 28 | desp=`grep '^## ' $1/bin/$file | cut -c 3-` 29 | if [ "$desp" != "" ]; then 30 | print_column "$file\t:$desp" 31 | echo "$file" >> $HOME/.opscripts/cmds.cache 32 | fi 33 | done 34 | echo '' 35 | } 36 | 37 | list_command() { 38 | rm -f $HOME/.opscripts/cmds.cache 2>/dev/null 39 | mkdir $HOME/.opscripts 2>/dev/null 40 | echo 'Available commands:' 41 | print_title bin 42 | find_command $OPSCRIPTS_DIR 43 | 44 | print_title java/bin 45 | find_command $OPSCRIPTS_DIR/java 46 | exit 0; 47 | } 48 | 49 | uninstall() { 50 | echo -n "Uninstall opscripts,(y)es or (n)o?" 51 | read choice < /dev/tty 52 | if [ "$choice" = "y" ] && [ "$OPSCRIPTS_DIR" != "/" ];then 53 | cd $OPSCRIPTS_DIR && make uninstall && rm -rf $OPSCRIPTS_DIR && echo "opscripts uninstall finished. Bye~" 54 | fi 55 | exit 0 56 | } 57 | -------------------------------------------------------------------------------- /tuning/java/bin/lib/jvm.list: -------------------------------------------------------------------------------- 1 | ========线程相关======= 2 | s;java -jar ${OPSCRIPTS_JVM_LIB}/jtop.jar -size H -thread 10 -stack 100 [arg] pid;查看占用cpu最高的线程情况;0,3;; 3 | b;jstack pid;打印所有线程;0;; 4 | a;echo -n "Thread count:"&&jstack pid |grep prio= |grep tid= |grep nid=|wc -l;打印线程数;0;; 5 | c;jstack pid |grep 'java.lang.Thread.State:'|sort|uniq -c;按线程状态统计线程数;0;; 6 | ========GC相关======= 7 | h;jstat -gccause pid [arg];垃圾收集统计(包含原因);0,3;可以指定间隔时间及执行次数,默认1秒, 10次;1000 10 8 | f;jstat -gccapacity pid [arg];显示堆中各代的空间;0,3;可以指定间隔时间及执行次数,默认1秒,5次;1000 5 9 | d;jstat -gcutil pid [arg];垃圾收集统计。;0,3;可以指定间隔时间及执行次数,默认1秒, 10次;1000 10 10 | l;jstat -gcpermcapacity pid [arg];打印perm区内存情况*会使程序暂停响应*;0; 11 | r;java -cp ${JAVA_HOME}/lib/tools.jar:${OPSCRIPTS_JVM_LIB} MonBuffers pid [arg] ;查看directbuffer情况;0,3;;1000 5 12 | ========堆对象相关======= 13 | m;jmap -dump:file=[arg] pid;dump heap到文件*会使程序暂停响应*;0; 默认保存到`pwd`/dump.bin,可指定其它路径;`pwd`/dump.bin 14 | e;jmap -histo:live pid [arg] >/dev/null;触发full gc。*会使程序暂停响应*;0; 15 | k;jmap -heap pid [arg];打印jvm heap统计*会使程序暂停响应*;0; 16 | k;jmap -histo pid |sort -n -r -k$(([arg]+1)) |head -n 21;打印jvm heap中top20的对象。*会使程序暂停响应*;0;参数:1:按实例数量排序,2:按内存占用排序,默认为1;1 17 | q;jmap -histo:live pid |sort -n -r -k$(([arg]+1)) |head -n 21;触发full gc后打印jvm heap中top20的对象。*会使程序暂停响应*;0;参数:1:按实例数量排序,2:按内存占用排序,默认为1;1 18 | p;jmap -permstat pid [arg];输出所有类装载器在perm里产生的对象。;0;可以指定间隔时间及执行次数 19 | ========其它======= 20 | g;jmap -finalizerinfo pid [arg];打印finalzer队列情况;0; 21 | j;jstat -class pid [arg];显示classloader统计;0,3; 22 | i;jstat -compiler pid [arg];显示jit编译统计;0,3; 23 | n;jstack -m pid ;死锁检测;0;; 24 | o;sleep [arg];等待X秒,默认为1;1,1;;1 25 | -------------------------------------------------------------------------------- /tuning/bin/xpl: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # @Function 3 | ## Open file in file explorer. 4 | # 5 | # @Usage 6 | # $ ./xpf file 7 | # 8 | # @author Jerry Lee 9 | 10 | PROG=`basename $0` 11 | 12 | usage() { 13 | cat </dev/null| awk '{ print $2 }'` 23 | do 24 | let SUM=$SUM+$SWAP 25 | done 26 | 27 | if [ $SUM != 0 ] ; then 28 | if [ $SORTED == true ] ; then 29 | STATISTICS=$STATISTICS+"PID=$PID - Swap used: $SUM k - ($PROGNAME )\n" 30 | else 31 | echo "PID=$PID - Swap used: $SUM k - ($PROGNAME )" 32 | fi 33 | fi 34 | 35 | let OVERALL=$OVERALL+$SUM 36 | SUM=0 37 | done 38 | 39 | if [ $SORTED == true ]; then 40 | if [ $REVERSE == true ]; then 41 | echo -e $STATISTICS | sort -nk 5 -r 42 | else 43 | echo -e $STATISTICS | sort -nk 5 44 | fi 45 | fi 46 | 47 | echo "Overall swap used: $OVERALL k" 48 | } 49 | 50 | SORTED=false 51 | REVERSE=false 52 | GREP_OPTARG="" 53 | 54 | while getopts "hsrg:" arg 55 | do 56 | case $arg in 57 | s) 58 | SORTED=true 59 | ;; 60 | r) 61 | REVERSE=true 62 | ;; 63 | g) 64 | GREP_OPTARG=$OPTARG 65 | ;; 66 | h) 67 | echo -e "Usage: sudo swap [-s[-r]] [-g GREP_ARG] 68 | -s sorted by swap used 69 | -r sorted reverse 70 | -g find specified process by 'grep' command 71 | " 72 | exit 0 73 | ;; 74 | ?) 75 | echo -e "Usage: sudo swap [-s[-r]] [-g GREP_ARG] 76 | 77 | -s sorted by swap used 78 | -r sorted reverse 79 | -g find specified process by 'grep' command 80 | " 81 | exit 1 ;; 82 | esac 83 | done 84 | 85 | if [ ! -f "/proc" ]; then 86 | echo "cannot read infomation from /proc, exit!" 87 | exit 1 88 | fi 89 | getswap $SORTED $REVERSE $GREP_OPTARG -------------------------------------------------------------------------------- /misc/git/clean_gitlab_pipeline.py: -------------------------------------------------------------------------------- 1 | """ 2 | @version: Python 3.7 3 | @author: deepglint 4 | @time: 2019/10/31 20:20 5 | @disclaimer:anyone can use this, but take responsibility yourself 6 | @BUG:if deletePageNum>actualPageNum, this code will delete about all pipelines 7 | """ 8 | 9 | import requests 10 | 11 | 12 | # Note: This must need the reposity's creator's access-token(maintainer's is forbidden also) 13 | PRIVATE_TOKEN = 'v-xxxxxxxxxxxxxx' 14 | 15 | 16 | def get_header(): 17 | headers = {} 18 | headers['PRIVATE-TOKEN'] = PRIVATE_TOKEN 19 | headers['Content-Type'] = "application/json" 20 | return headers 21 | 22 | 23 | ''' 24 | https://docs.gitlab.com/ee/api/pipelines.html#list-project-pipelines 25 | ''' 26 | 27 | 28 | def pipeline_clean(project_id, deletePageNum): 29 | ''' 30 | :param project_id: gitlab project id 31 | :param deletePageNum: 想要删除pipeline页数,每页20个pipeline,所以总共删除 20*deletePageNum 条记录(但是会保留第一页) 32 | :param deletePageNum: pipeline pages that you want to delete; twenty pipelines per page, so totally you will delete 20*deletePageNum pipeline records 33 | ''' 34 | gitlab_api_url = "https://gitlab.unionfab.com/api/v4/projects/" 35 | pipeline_list_Url = gitlab_api_url + str(project_id) + "/pipelines" 36 | pipeline_delete_Url = gitlab_api_url + str(project_id) + "/pipelines" 37 | 38 | if (deletePageNum) <= 1: 39 | return 40 | 41 | # loop to delete in last page 42 | for i in range(deletePageNum): 43 | params = { 44 | "sort": "asc" 45 | } 46 | response = requests.get(url=pipeline_list_Url, 47 | headers=get_header(), params=params) 48 | if len(response.json()) < 20: 49 | return 50 | if str(response.status_code).startswith("20"): 51 | for pipeline in response.json(): 52 | pipeline_id = pipeline["id"] 53 | delete_url = pipeline_delete_Url+"/"+str(pipeline_id) 54 | delete_response = requests.delete( 55 | url=delete_url, headers=get_header()) 56 | if str(delete_response.status_code).startswith("20"): 57 | print("page number "+str(i+1) + 58 | ", delete success: ", delete_url) 59 | else: 60 | print("page number "+str(i+1) + 61 | ", delete failed: ", delete_url) 62 | 63 | 64 | if __name__ == "__main__": 65 | pipeline_clean(project_id=243, deletePageNum=5) 66 | -------------------------------------------------------------------------------- /tuning/java/bin/lib/jvm.dsc: -------------------------------------------------------------------------------- 1 | j:Column | Description 2 | j:Loaded | 被读入类的数量 3 | j:Bytes | 被读入的字节数(K) 4 | j:Unloaded | 被卸载类的数量 5 | j:Bytes | 被卸载的字节数(K) 6 | j:Time | 花费在load和unload类的时间 7 | 8 | i:Column | Description 9 | i:Compiled | 被执行的编译任务的数量 10 | i:Failed | 失败的编译任务的数量 11 | i:Invalid | 无效的编译任务的数量 12 | i:Time | 花费在执行编译任务的时间. 13 | i:FailedType | 最近失败编译的编译类弄. 14 | i:FailedMethod | 最近失败编译的类名和方法名 15 | 16 | f:Column | Description 17 | f:NGCMN | 年轻代的最小容量 (KB). 18 | f:NGCMX | 年轻代的最大容量 (KB). 19 | f:NGC | 当前年轻代的容量 (KB). 20 | f:S0C | 当前S0的空间 (KB). 21 | f:S1C | 当前S1的空间 (KB). 22 | f:EC | 当前eden的空间 (KB). 23 | f:OGCMN | 年老代的最小容量 (KB). 24 | f:OGCMX | 年老代的最大容量 (KB). 25 | f:OGC | 当前年老代的容量 (KB). 26 | f:OC | 当前年老代的空间 (KB). 27 | f:PGCMN | 永久代的最小容量 (KB). 28 | f:PGCMX | 永久代的最大容量 (KB). 29 | f:PGC | 当前永久代的容量 (KB). 30 | f:PC | 当前永久代的空间 (KB). 31 | f:YGC | 年轻代gc的次数 32 | f:FGC | full gc的次数 33 | 34 | d:Column | Description 35 | d:S0 | S0使用百分比 36 | d:S1 | S1使用百分比 37 | d:E | eden使用百分比 38 | d:O | old使用百分比 39 | d:P | perm使用百分比 40 | d:YGC | 年轻代gc次数 41 | d:YGCT | 年轻代gc时间 42 | d:FGC | full gc次数 43 | d:FGCT | full gc时间 44 | d:GCT | 垃圾收集总时间 45 | 46 | h:Column | Description 47 | h:S0 | S0使用百分比 48 | h:S1 | S1使用百分比 49 | h:E | eden使用百分比 50 | h:O | old使用百分比 51 | h:P | perm使用百分比 52 | h:YGC | 年轻代gc次数 53 | h:YGCT | 年轻代gc时间 54 | h:FGC | full gc次数 55 | h:FGCT | full gc时间 56 | h:GCT | 垃圾收集总时间 57 | h:LGCC | 最近垃圾回收的原因. 58 | h:GCC | 当前垃圾回收的原因. 59 | 60 | p:输出所有类装载器在堆里产生的对象 包括每个装载器的名字,活跃,地址,父装载器,和其总共加载的类大小 61 | 62 | 63 | l:Column | Description 64 | l:PGCMN | 永久代最小容量 (KB). 65 | l:PGCMX | 永久代最大容量 (KB). 66 | l:PGC | 当前永久代的容量 (KB). 67 | l:PC | 当前永久代的空间 (KB). 68 | l:YGC | 年轻代gc次数 69 | l:FGC | full gc次数 70 | l:FGCT | full gc时间 71 | l:GCT | 垃圾收集总时间 72 | 73 | k:class name对应的就是Class文件里的class的标识 74 | k:B代表byte 75 | k:C代表char 76 | k:D代表double 77 | k:F代表float 78 | k:I代表int 79 | k:J代表long 80 | k:Z代表boolean 81 | k:前边有[代表数组 82 | k:对象用[L+类名表示 83 | 84 | q:class name对应的就是Class文件里的class的标识 85 | q:B代表byte 86 | q:C代表char 87 | q:D代表double 88 | q:F代表float 89 | q:I代表int 90 | q:J代表long 91 | q:Z代表boolean 92 | q:前边有[代表数组 93 | q:对象用[L+类名表示 94 | 95 | r:应用程序的directbuffer使用情况(单位为byte) 96 | r:direct代表ByteBuffer.allocateDirect分配的nio directbuffer 97 | r:mapped代表FileChannel.map分配的mapped memory 98 | 99 | s:查看占用cpu最高的线程情况 100 | s:使用了开源项目jtop,项目地址:https://bitbucket.org/hatterjiang/jtop,作者:hatterjiang 101 | -------------------------------------------------------------------------------- /harden/harden/basic.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # desc: setup linux system security 3 | 4 | # account setup 5 | passwd -l xfs 6 | passwd -l news 7 | passwd -l nscd 8 | passwd -l dbus 9 | passwd -l vcsa 10 | passwd -l games 11 | passwd -l nobody 12 | passwd -l avahi 13 | passwd -l haldaemon 14 | passwd -l gopher 15 | passwd -l ftp 16 | passwd -l mailnull 17 | passwd -l pcap 18 | passwd -l mail 19 | passwd -l shutdown 20 | passwd -l halt 21 | passwd -l uucp 22 | passwd -l operator 23 | passwd -l sync 24 | passwd -l adm 25 | passwd -l lp 26 | 27 | # chattr /etc/passwd /etc/shadow 28 | chattr +i /etc/passwd 29 | chattr +i /etc/shadow 30 | chattr +i /etc/group 31 | chattr +i /etc/gshadow 32 | # add continue input failure 3 ,passwd unlock time 5 minite 33 | sed -i 's#auth required pam_env.so#auth required pam_env.so\nauth required pam_tally.so onerr=fail deny=3 unlock_time=300\nauth required /lib/security/$ISA/pam_tally.so onerr=fail deny=3 unlock_time=300#' /etc/pam.d/system-auth 34 | # system timeout 5 minite auto logout 35 | echo "TMOUT=300" >>/etc/profile 36 | 37 | # will system save history command list to 10 38 | sed -i "s/HISTSIZE=1000/HISTSIZE=10/" /etc/profile 39 | 40 | # enable /etc/profile go! 41 | source /etc/profile 42 | 43 | # add syncookie enable /etc/sysctl.conf 44 | echo "net.ipv4.tcp_syncookies=1" >> /etc/sysctl.conf 45 | 46 | sysctl -p # exec sysctl.conf enable 47 | # optimizer sshd_config 48 | 49 | sed -i "s/#MaxAuthTries 6/MaxAuthTries 6/" /etc/ssh/sshd_config 50 | sed -i "s/#UseDNS yes/UseDNS no/" /etc/ssh/sshd_config 51 | 52 | # limit chmod important commands 53 | chmod 700 /bin/ping 54 | chmod 700 /usr/bin/finger 55 | chmod 700 /usr/bin/who 56 | chmod 700 /usr/bin/w 57 | chmod 700 /usr/bin/locate 58 | chmod 700 /usr/bin/whereis 59 | chmod 700 /sbin/ifconfig 60 | chmod 700 /usr/bin/pico 61 | chmod 700 /bin/vi 62 | chmod 700 /usr/bin/which 63 | chmod 700 /usr/bin/gcc 64 | chmod 700 /usr/bin/make 65 | chmod 700 /bin/rpm 66 | 67 | # history security 68 | 69 | chattr +a /root/.bash_history 70 | chattr +i /root/.bash_history 71 | 72 | # write important command md5 73 | cat > list << "EOF" && 74 | /bin/ping 75 | /bin/finger 76 | /usr/bin/who 77 | /usr/bin/w 78 | /usr/bin/locate 79 | /usr/bin/whereis 80 | /sbin/ifconfig 81 | /bin/pico 82 | /bin/vi 83 | /usr/bin/vim 84 | /usr/bin/which 85 | /usr/bin/gcc 86 | /usr/bin/make 87 | /bin/rpm 88 | EOF 89 | 90 | for i in `cat list` 91 | do 92 | if [ ! -x $i ];then 93 | echo "$i not found,no md5sum!" 94 | else 95 | md5sum $i >> /var/log/`hostname`.log 96 | fi 97 | done 98 | rm -f list 99 | 100 | -------------------------------------------------------------------------------- /tuning/bin/monitor-host: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # @Function 3 | ## monitor host:network io memory cpu 4 | # 5 | # @Usage 6 | # $ ./monitor-host.sh 7 | # 8 | # @author Bryant Hang 9 | 10 | readonly PROG=`basename $0` 11 | 12 | usage() { 13 | local out 14 | [ -n "$1" -a "$1" != 0 ] && out=/dev/stderr || out=/dev/stdout 15 | 16 | > $out cat < /tmp/MONIOTR_PIDS 41 | echo 42 | echo 'Done stop monitor threads...' 43 | 44 | exit 0 45 | } 46 | 47 | readonly ARGS=`getopt -n "$PROG" -a -o l:h -l log-path:,help:,stop -- "$@"` 48 | [ $? -ne 0 ] && usage 1 49 | eval set -- "${ARGS}" 50 | 51 | while true; do 52 | case "$1" in 53 | -l|--log-path) 54 | log_path="$2" 55 | shift 2 56 | ;; 57 | --stop) 58 | stop 59 | ;; 60 | -h|--help) 61 | usage 62 | ;; 63 | --) 64 | shift 65 | break 66 | ;; 67 | esac 68 | done 69 | 70 | delay=${1:-1} 71 | count=${2:-10} 72 | log_path=${log_path:-'monitor_logs'} 73 | 74 | if ! [ -d $log_path ]; then 75 | mkdir -p $log_path 76 | fi 77 | 78 | readonly cur_date="`date +%Y%m%d`" 79 | 80 | readonly top_log_path=$log_path'/top_'$cur_date'.log' 81 | readonly memory_log_path=$log_path'/memory_'$cur_date'.log' 82 | readonly cpu_log_path=$log_path'/cpu_'$cur_date'.log' 83 | readonly io_log_path=$log_path'/io_'$cur_date'.log' 84 | readonly network_log_path=$log_path'/network_'$cur_date'.log' 85 | 86 | echo -n > /tmp/MONIOTR_PIDS 87 | # total performance check 88 | top -b -d $delay -n $count >> $top_log_path 2>&1 & 89 | echo $! >> /tmp/MONIOTR_PIDS 90 | 91 | # memory check 92 | vmstat $delay $count >> $memory_log_path 2>&1 & 93 | echo $! >> /tmp/MONIOTR_PIDS 94 | 95 | # cpu check 96 | sar -u $delay $count >> $cpu_log_path 2>&1 & 97 | echo $! >> /tmp/MONIOTR_PIDS 98 | 99 | # IO check 100 | iostat $delay $count >> $io_log_path 2>&1 & 101 | echo $! >> /tmp/MONIOTR_PIDS 102 | 103 | # network check 104 | sar -n DEV $delay $count >> $network_log_path 2>&1 & 105 | echo $! >> /tmp/MONIOTR_PIDS 106 | 107 | echo 'Output logs to '$log_path'....' 108 | -------------------------------------------------------------------------------- /tuning/bin/svn-merge-stop-on-copy: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # @Function 3 | ## svn merge commit between verison when source branch copy(--stop-on-copy) and head version of source branch. 4 | # 5 | # @Usage 6 | # $ ./svnmerge.sh [target branch] 7 | # if no target branch, merge to current svn direcotry 8 | # 9 | # @author jiangjizhong(@jzwlqx) 10 | # @author Jerry Lee 11 | 12 | PROG=`basename $0` 13 | 14 | usage() { 15 | cat < [target branch] 17 | svn merge commit between verison when source branch copy(--stop-on-copy) 18 | and head version of source branch. 19 | Source branch must be a remote branch. 20 | 21 | Example: 22 | ${PROG} http://www.foo.com/project1/branches/feature1 23 | # merge http://www.foo.com/project1/branches/feature1 to current svn direcotry 24 | 25 | ${PROG} http://www.foo.com/project1/branches/feature1 /path/to/svn/direcotry 26 | # merge branch http://www.foo.com/project1/branches/feature1 to svn direcotry /path/to/svn/direcotry 27 | # will prompt comfirm for committing to target branch. 28 | 29 | ${PROG} http://www.foo.com/project1/branches/feature1 http://www.foo.com/project1/branches/feature2 30 | # merge http://www.foo.com/project1/branches/feature1 to branch http://www.foo.com/project1/branches/feature2 31 | # because http://www.foo.com/project1/branches/feature2 is remote url, 32 | # will check out target branch to tmp direcotry, and prompt comfirm for committing to target branch. 33 | EOF 34 | exit $1 35 | } 36 | 37 | [ $# -gt 2 ] && { 38 | echo "too many arguments!" 39 | usage 1 40 | } 41 | 42 | source_branch=$1 43 | target=${2:-.} 44 | 45 | [ -z "$source_branch" ] && { 46 | echo "missing source branch argument!" 47 | usage 1 48 | } 49 | [ -e "$source_branch" ] && { 50 | echo "source branch must be a remote branch!" 51 | usage 1 52 | } 53 | 54 | [ ! -d "$target" ] && { 55 | workDir=$(mktemp -d) && svn co "$target" "$workDir" || { 56 | echo "Fail to checkout target remote branch $target !" 57 | exit 1 58 | } 59 | } || workDir="$target" 60 | 61 | cleanup() { 62 | [ "$workDir" != "$target" ] && { 63 | echo "rm tmp dir $workDir ." 64 | rm -rf "$workDir" 65 | } 66 | } 67 | trap "cleanup" EXIT 68 | 69 | svnstatusline=$(svn status --ignore-externals "$workDir" | grep -v ^X | wc -l) 70 | [ "$svnstatusline" -ne 0 ] && { 71 | echo "svn work direcotry is modified!" 72 | exit 1 73 | } 74 | 75 | cd "$workDir" && 76 | from_version=$(svn log --stop-on-copy --quiet "$source_branch" | awk '$1~/^r[0-9]+/{print $1}' | tail -n1) && { 77 | echo "oldest version($from_version) of source branch $source_branch ." 78 | echo "starting merge to $workDir ." 79 | svn merge -${from_version}:HEAD $source_branch 80 | } || { 81 | echo "Fail to merge to work dir $workDir ." 82 | exit 2 83 | } 84 | 85 | read -p "Check In? (Y/N)" ci 86 | [ "$ci" = "Y" ] && svn ci -m "svn merge -${from_version}:HEAD $source_branch" 87 | -------------------------------------------------------------------------------- /tuning/java/bin/lib/MonBuffers.java: -------------------------------------------------------------------------------- 1 | import java.io.File; 2 | import java.util.*; 3 | import java.lang.management.BufferPoolMXBean; 4 | import java.lang.management.ManagementFactory; 5 | import javax.management.MBeanServerConnection; 6 | import javax.management.ObjectName; 7 | import javax.management.remote.*; 8 | 9 | import com.sun.tools.attach.VirtualMachine; // Attach API 10 | 11 | /** 12 | * Simple tool to attach to running VM to report buffer pool usage. 13 | */ 14 | 15 | public class MonBuffers { 16 | static final String CONNECTOR_ADDRESS = 17 | "com.sun.management.jmxremote.localConnectorAddress"; 18 | private static void logo() { 19 | System.out.println("Usage:java -cp $JAVA_HOME/lib/tools.jar:. MonBuffers [interval] [count]"); 20 | System.exit(1); 21 | } 22 | 23 | public static void main(String args[]) throws Exception { 24 | // attach to target VM to get connector address 25 | int sleep = 1000; 26 | int count = 10; 27 | 28 | if(args.length == 0) { 29 | logo(); 30 | } 31 | if (args.length > 1) { 32 | try { 33 | sleep = Integer.parseInt(args[1]); 34 | } catch(Exception e) { 35 | logo(); 36 | } 37 | } 38 | if (args.length >2) { 39 | try { 40 | count = Integer.parseInt(args[2]); 41 | } catch(Exception e) { 42 | logo(); 43 | } 44 | } 45 | System.out.println("start monitor DirectBuffer,pid:"+args[0]+",interval:"+sleep+",count:"+count); 46 | 47 | VirtualMachine vm = VirtualMachine.attach(args[0]); 48 | String connectorAddress = vm.getAgentProperties().getProperty(CONNECTOR_ADDRESS); 49 | if (connectorAddress == null) { 50 | // start management agent 51 | String agent = vm.getSystemProperties().getProperty("java.home") + 52 | File.separator + "lib" + File.separator + "management-agent.jar"; 53 | vm.loadAgent(agent); 54 | connectorAddress = vm.getAgentProperties().getProperty(CONNECTOR_ADDRESS); 55 | assert connectorAddress != null; 56 | } 57 | 58 | // connect to agent 59 | JMXServiceURL url = new JMXServiceURL(connectorAddress); 60 | JMXConnector c = JMXConnectorFactory.connect(url); 61 | MBeanServerConnection server = c.getMBeanServerConnection(); 62 | 63 | // get the list of pools 64 | Set mbeans = server.queryNames( 65 | new ObjectName("java.nio:type=BufferPool,*"), null); 66 | List pools = new ArrayList(); 67 | for (ObjectName name: mbeans) { 68 | BufferPoolMXBean pool = ManagementFactory 69 | .newPlatformMXBeanProxy(server, name.toString(), BufferPoolMXBean.class); 70 | pools.add(pool); 71 | } 72 | 73 | // print headers 74 | for (BufferPoolMXBean pool: pools) 75 | System.out.format(" %8s ", pool.getName()); 76 | System.out.println(); 77 | for (int i=0; i/dev/null ] && [ "$choice" -lt "4" 2>/dev/null ]; then 12 | return $choice; 13 | else 14 | echo "$choice is not valid option!" 15 | fi 16 | done 17 | } 18 | 19 | do_download(){ 20 | fetch_dir=$1; 21 | if [ ! -d $fetch_dir ]; then 22 | echo "$fetch_dir is not vaild!" 23 | exit 1; 24 | fi 25 | cd $fetch_dir 26 | test_exists $fetch_dir 27 | set +e 28 | type "git" >/dev/null 2>/dev/null 29 | has_git=$? 30 | set -e 31 | if [ "$has_git" -eq 0 ];then 32 | echo "fetching source from github" 33 | do_fetch $fetch_dir; 34 | else 35 | set +e 36 | type "svn" >/dev/null 2>/dev/null 37 | has_svn=$? 38 | set -e 39 | if [ "$has_svn" -eq 0 ];then 40 | echo "fetching source from github using svn" 41 | do_fetch $fetch_dir svn; 42 | else 43 | echo "can't locate svn ,using archive mode." 44 | do_download_archive $fetch_dir; 45 | fi 46 | fi 47 | echo "awesome-scripts is downloaded to $fetch_dir/awesome-scripts" 48 | } 49 | 50 | do_download_archive(){ 51 | wget https://codeload.github.com/superhj1987/awesome-scripts/zip/master -O awesome-scripts.zip 52 | unzip awesome-scripts.zip 53 | rm -rf awesome-scripts.zip 54 | mv awesome-scripts-master awesome-scripts 55 | cd awesome-scripts 56 | } 57 | 58 | do_fetch(){ 59 | fetch_dir=$1; 60 | if [ ! -d $fetch_dir ]; then 61 | echo "$fetch_dir is not vaild!" 62 | exit 1; 63 | fi 64 | cd $fetch_dir ; 65 | test_exists awesome-scripts; 66 | if [[ $# < 2 || "$2" = "git" ]]; then 67 | git clone https://github.com/superhj1987/awesome-scripts.git awesome-scripts --depth=1 68 | else 69 | svn checkout https://github.com/superhj1987/awesome-scripts/trunk awesome-scripts 70 | fi 71 | cd awesome-scripts 72 | return 0 73 | } 74 | 75 | test_exists(){ 76 | if [ -e awesome-scripts ]; then 77 | echo "$1/awesome-scripts already exist!" 78 | while(true);do 79 | echo -n "(q)uit or (r)eplace?" 80 | read choice < /dev/tty 81 | if [ "$choice" = "q" ];then 82 | exit 0; 83 | elif [ "$choice" = "r" ];then 84 | rm -fr $1/awesome-scripts 85 | break; 86 | else 87 | echo "$choice is not valid!" 88 | fi 89 | done 90 | fi 91 | } 92 | 93 | do_install(){ 94 | echo '***install need sudo,please enter password***' 95 | sudo make install 96 | echo 'awesome-scripts was installed to /usr/local/bin,have fun.' 97 | } 98 | 99 | main(){ 100 | getType 101 | type=$? 102 | set -e 103 | case "$type" in 104 | ("1") 105 | echo "Launching awesome-scripts installer..." 106 | do_download `pwd` 107 | do_install 108 | ;; 109 | ("2") 110 | echo "Start downloading awesome-scripts ..." 111 | do_download `pwd` 112 | ;; 113 | esac 114 | } 115 | 116 | main "$@" -------------------------------------------------------------------------------- /tuning/java/bin/jvm: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ## start jvm debugger 3 | 4 | if [ $# -lt 1 ];then 5 | echo "Usage : jvm "; 6 | exit 1; 7 | fi 8 | p(){ 9 | if [ "$output_flag" = "1" ];then 10 | echo "$@" 11 | elif [ "$output_flag" = "2" ];then 12 | echo "$@" >>${pid}_jvm.log 13 | else 14 | echo "$@" |tee -a ${pid}_jvm.log 15 | fi 16 | } 17 | 18 | doMain(){ 19 | while(true) ;do 20 | i=1 21 | while read line ;do 22 | if [[ "$line" == "="* ]];then 23 | echo "$line" 24 | continue; 25 | elif [[ "$line" == "#"* ]];then 26 | echo "$line" 27 | continue; 28 | fi 29 | OLD_IFS="$IFS" 30 | IFS=";" 31 | defs=($line) 32 | IFS="$OLD_IFS" 33 | eval marker${i}=\'${defs[0]}\' 34 | eval cmd_def${i}=\'${defs[1]}\' 35 | eval desp_def${i}=\'${defs[2]}\' 36 | eval arg_def${i}=\'${defs[3]}\' 37 | eval arg_desp${i}=\'${defs[4]}\' 38 | eval def_arg${i}=\'${defs[5]}\' 39 | echo $i" : "$(eval echo \$desp_def${i})$(eval echo \$arg_desp${i}) 40 | ((i++)) 41 | done < $base_dir/lib/jvm.list 42 | echo "q : exit" 43 | echo -n "Enter command queue:" 44 | read input < /dev/tty 45 | if [ "$input" = "q" ];then exit 0;fi 46 | if [ "$input" = "" ];then continue;fi 47 | OLD_IFS=”$IFS” 48 | IFS=”\;” 49 | choices=($input) 50 | IFS=”$OLD_IFS” 51 | if [ "$input" = "q" ];then exit 0;fi 52 | cmd_queue=$input 53 | echo "which output type?" 54 | echo "default : console and log file(${1}_jvm.log)" 55 | echo "a : console only" 56 | echo "b : file only" 57 | echo -n "Enter output type:" 58 | read input < /dev/tty 59 | if [ "$input" = "a" ];then 60 | output_flag="1" 61 | elif [ "$input" = "b" ];then 62 | output_flag="2" 63 | else 64 | output_flag="" 65 | fi 66 | p "=======================================================" 67 | p "*** [`date "+%Y-%m-%d %H:%M:%S"`] start execute queue : $cmd_queue ***" 68 | for choice in ${choices[@]}; do 69 | OLD_IFS=”$IFS” 70 | IFS=”:” 71 | cmd=($choice) 72 | IFS=”$OLD_IFS” 73 | actul_cmd=$(eval echo \$cmd_def${cmd[0]}) 74 | actul_cmd=${actul_cmd//pid/$1} 75 | arg=${cmd[1]} 76 | if [ "$arg" = "" ];then 77 | arg="$(eval echo \$def_arg${cmd[0]})" 78 | fi 79 | arg=${arg//,/ } 80 | actul_cmd=${actul_cmd//\[arg\]/$arg} 81 | mark=$(eval echo \$marker${cmd[0]}) 82 | help_msg=`cat ${base_dir}/lib/jvm.dsc | grep -e "^${mark}:"|cut -c 3-` 83 | p "-------------------------------------------------------" 84 | p "*** [`date "+%Y-%m-%d %H:%M:%S"`] start execute command:$actul_cmd ***" 85 | p "*** [`date "+%Y-%m-%d %H:%M:%S"`] $(eval echo \$desp_def${cmd[0]}) ***" 86 | if [ ! "$help_msg" = "" ];then 87 | help_msg=`echo "$help_msg"|awk '{print "# "$0}'` 88 | p "# Help message:" 89 | p -e "$help_msg" 90 | p "" 91 | fi 92 | if [ "$output_flag" = "1" ];then 93 | bash -c "export OPSCRIPTS_JVM_LIB=${base_dir}/lib; $actul_cmd" 2>&1 94 | elif [ "$output_flag" = "2" ];then 95 | bash -c "export OPSCRIPTS_JVM_LIB=${base_dir}/lib; $actul_cmd" > ${pid}_jvm.log 2>&1 96 | else 97 | bash -c "export OPSCRIPTS_JVM_LIB=${base_dir}/lib; $actul_cmd" | tee -a ${pid}_jvm.log 98 | fi 99 | p "*** [`date "+%Y-%m-%d %H:%M:%S"`] finish execute command:$actul_cmd ***" 100 | done 101 | p "*** [`date "+%Y-%m-%d %H:%M:%S"`] finish execute queue ***" 102 | p "=======================================================" 103 | done 104 | } 105 | 106 | pid=$1 107 | base_dir=$(dirname "$(echo "$0" | sed -e '')") 108 | doMain "$@" -------------------------------------------------------------------------------- /tuning/docs/vcs.md: -------------------------------------------------------------------------------- 1 | :snail: `VCS`相关脚本 2 | ==================================== 3 | 4 | > 你会发现这些脚本都是`svn`分支相关的操作。 5 | > 6 | > 个人在使用`Git`的过程中(7年+),并没有发现有对应脚本的需求(侧面反映出`Git`的优秀)。 7 | > 原因:`Git`的概念模型一等公民支持分支,切换分支是件很简单且统一的事,而`svn`不得不涉及仓库的`URL`(不统一简单)。 8 | > 9 | > 我已经在自己的开发机上卸载了`svn`,没有需求场景也没理由再用了。 :stuck_out_tongue: 10 | > 11 | > 使用更现代的`Git`吧! :boom: 12 | 13 | 1. [swtrunk](docs/vcs.md#beer-swtrunk) 14 | 自动`svn`工作目录从分支(`branches`)切换到主干(`trunk`)。 15 | PS: `Git`对应的是`git checkout master`,如果你使用了`oh-my-zsh`,已经有对应的别名加速了:`gcm`。 16 | 1. [svn-merge-stop-on-copy](docs/vcs.md#beer-svn-merge-stop-on-copy) 17 | 把指定的远程分支从刚新建分支以来的修改合并到本地`svn`目录或是另一个远程分支。 18 | PS:`Git`的合并很直接简单,`git merge branch-foo`,也更智能(没有树冲突一说)。 19 | 1. [cp-svn-url](docs/vcs.md#beer-cp-svn-url) 20 | 拷贝当前`svn`目录对应的远程分支到系统的粘贴板,省去`CTRL+C`操作。 21 | PS:`Git`分支不需要`URL`来引用,没有这个脚本的需求,直接给个分支名就好了。 22 | 23 | :beer: [swtrunk](../bin/swtrunk) 24 | ---------------------- 25 | 26 | `svn`工作目录从分支(`branches`)切换到主干(`trunk`)。 27 | 支持`Linux`、`Mac`、`Windows`(`cygwin`、`MSSYS`)。 28 | 29 | 命令以`svn`的标准目录命名约定来识别分支和主干。 30 | 即,分支在目录`branches`下,主干在目录`trunk`下。 31 | 示例: 32 | - 分支: http://www.foo.com/project1/branches/feature1 33 | - 主干: http://www.foo.com/project1/trunk 34 | 35 | ### 用法 36 | 37 | ```bash 38 | swtrunk # 缺省使用当前目录作为svn工作目录 39 | cp-svn-url /path/to/svn/work/directory 40 | cp-svn-url /path/to/svn/work/directory1 /path/to/svn/work/directory2 # svn工作目录个数不限制 41 | ``` 42 | 43 | ### 示例 44 | 45 | ```bash 46 | $ swtrunk 47 | # 48 | svn work dir . switch from http://www.foo.com/project1/branches/feature1 to http://www.foo.com/project1/trunk ! 49 | 50 | $ swtrunk /path/to/svn/work/dir 51 | # 52 | svn work dir /path/to/svn/work/dir switch from http://www.foo.com/project1/branches/feature1 to http://www.foo.com/project1/trunk ! 53 | 54 | $ swtrunk /path/to/svn/work/dir1 /path/to/svn/work/dir2 55 | # 56 | svn work dir /path/to/svn/work/dir1 switch from http://www.foo.com/project1/branches/feature1 to http://www.foo.com/project1/trunk ! 57 | # 58 | svn work dir /path/to/svn/work/dir2 switch from http://www.foo.com/project2/branches/feature1 to http://www.foo.com/project2/trunk ! 59 | ``` 60 | 61 | :beer: [svn-merge-stop-on-copy](../bin/svn-merge-stop-on-copy) 62 | ---------------------- 63 | 64 | 把指定的远程分支从刚新建分支以来的修改合并到本地`svn`目录或是另一个远程分支。 65 | 支持`Linux`、`Mac`、`Windows`(`cygwin`、`MSSYS`)。 66 | 67 | ### 用法 68 | 69 | ```bash 70 | svn-merge-stop-on-copy <来源的远程分支> # 合并当前本地svn目录 71 | svn-merge-stop-on-copy <来源的远程分支> <目标本地svn目录> 72 | svn-merge-stop-on-copy <来源的远程分支> <目标远程分支> 73 | ``` 74 | 75 | ### 示例 76 | 77 | ```bash 78 | svn-merge-stop-on-copy http://www.foo.com/project1/branches/feature1 # 缺省使用当前目录作为svn工作目录 79 | svn-merge-stop-on-copy http://www.foo.com/project1/branches/feature1 /path/to/svn/work/directory 80 | svn-merge-stop-on-copy http://www.foo.com/project1/branches/feature1 http://www.foo.com/project1/branches/feature2 81 | ``` 82 | 83 | ### 贡献者 84 | 85 | [姜太公](https://github.com/jzwlqx)提供此脚本。 86 | 87 | :beer: [cp-svn-url](../bin/cp-svn-url) 88 | ---------------------- 89 | 90 | 拷贝当前`svn`目录对应的远程分支到系统的粘贴板,省去`CTRL+C`操作。 91 | 支持`Linux`、`Mac`、`Windows`(`cygwin`、`MSSYS`)。 92 | 93 | ### 用法 94 | 95 | ```bash 96 | cp-svn-url # 缺省使用当前目录作为svn工作目录 97 | cp-svn-url /path/to/svn/work/directory 98 | ``` 99 | 100 | ### 示例 101 | 102 | ```bash 103 | $ cp-svn-url 104 | http://www.foo.com/project1/branches/feature1 copied! 105 | ``` 106 | 107 | ### 贡献者 108 | 109 | [ivanzhangwb](https://github.com/ivanzhangwb)提供此脚本。 110 | 111 | ### 参考资料 112 | 113 | [拷贝复制命令行输出放在系统剪贴板上](http://oldratlee.com/post/2012-12-23/command-output-to-clip),给出了不同系统可用命令。 114 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # devops-scripts 2 | 3 | 本项目是对于 [Backend-Boilerplates](https://github.com/wx-chevalier/Backend-Boilerplates) 项目中常见的运维脚本的提取与归纳。目前包含以下类别: 4 | 5 | - misc: 杂项 6 | 7 | - tuning: 系统监控与性能调优 8 | 9 | - harden: 系统加固 10 | 11 | # About 12 | 13 | ## Motivation & Credit 14 | 15 | - [useful-scripts](https://github.com/oldratlee/useful-scripts): 🐌 useful scripts for making developer's everyday life easier and happier, involved java, shell etc. 16 | 17 | - [awesome-scripts](https://github.com/superhj1987/awesome-scripts): useful scripts for Linux op. 18 | 19 | - https://www.kancloud.cn/ningjing_home/ceph/458304 20 | 21 | ## 版权 22 | 23 | ![License: CC BY-NC-SA 4.0](https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-lightgrey.svg) 24 | ![](https://parg.co/bDm) 25 | 26 | 笔者所有文章遵循 [知识共享 署名-非商业性使用-禁止演绎 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-nd/4.0/deed.zh),欢迎转载,尊重版权。如果觉得本系列对你有所帮助,欢迎给我家布丁买点狗粮(支付宝扫码)~ 27 | 28 | ![default](https://i.postimg.cc/y1QXgJ6f/image.png) 29 | 30 | ## Home & More | 延伸阅读 31 | 32 | ![技术视野](https://s2.ax1x.com/2019/09/30/uJWQTx.jpg) 33 | 34 | 您可以通过以下导航来在 Gitbook 中阅读笔者的系列文章,涵盖了技术资料归纳、编程语言与理论、Web 与大前端、服务端开发与基础架构、云计算与大数据、数据科学与人工智能、产品设计等多个领域: 35 | 36 | - 知识体系:《[Awesome Lists | CS 资料集锦](https://ngte-al.gitbook.io/i/)》、《[Awesome CheatSheets | 速学速查手册](https://ngte-ac.gitbook.io/i/)》、《[Awesome Interviews | 求职面试必备](https://github.com/wx-chevalier/Awesome-Interviews)》、《[Awesome RoadMaps | 程序员进阶指南](https://github.com/wx-chevalier/Awesome-RoadMaps)》、《[Awesome MindMaps | 知识脉络思维脑图](https://github.com/wx-chevalier/Awesome-MindMaps)》、《[Awesome-CS-Books | 开源书籍(.pdf)汇总](https://github.com/wx-chevalier/Awesome-CS-Books)》 37 | 38 | - 编程语言:《[编程语言理论](https://ngte-pl.gitbook.io/i/)》、《[Java 实战](https://github.com/wx-chevalier/Java-Series)》、《[JavaScript 实战](https://github.com/wx-chevalier/JavaScript-Series)》、《[Go 实战](https://ngte-pl.gitbook.io/i/go/go)》、《[Python 实战](https://ngte-pl.gitbook.io/i/python/python)》、《[Rust 实战](https://ngte-pl.gitbook.io/i/rust/rust)》 39 | 40 | - 软件工程、模式与架构:《[编程范式与设计模式](https://ngte-se.gitbook.io/i/)》、《[数据结构与算法](https://ngte-se.gitbook.io/i/)》、《[软件架构设计](https://ngte-se.gitbook.io/i/)》、《[整洁与重构](https://ngte-se.gitbook.io/i/)》、《[研发方式与工具](https://ngte-se.gitbook.io/i/)》 41 | 42 | * Web 与大前端:《[现代 Web 全栈开发与工程架构](https://ngte-web.gitbook.io/i/)》、《[数据可视化](https://ngte-fe.gitbook.io/i/)》、《[iOS](https://ngte-fe.gitbook.io/i/)》、《[Android](https://ngte-fe.gitbook.io/i/)》、《[混合开发与跨端应用](https://ngte-fe.gitbook.io/i/)》 43 | 44 | * 服务端开发实践与工程架构:《[微服务与云原生](https://ngte-be.gitbook.io/i/)》、《[测试与高可用保障](https://ngte-be.gitbook.io/i/)》、《[DevOps](https://ngte-be.gitbook.io/i/)》、《[Spring](https://github.com/wx-chevalier/Spring-Series)》、《[信息安全与渗透测试](https://ngte-be.gitbook.io/i/)》 45 | 46 | * 分布式基础架构:《[分布式系统](https://ngte-infras.gitbook.io/i/)》、《[分布式计算](https://ngte-infras.gitbook.io/i/)》、《[数据库](https://github.com/wx-chevalier/Database-Series)》、《[网络](https://ngte-infras.gitbook.io/i/)》、《[虚拟化与云计算](https://github.com/wx-chevalier/Cloud-Series)》、《[Linux 与操作系统](https://github.com/wx-chevalier/Linux-Series)》 47 | 48 | * 数据科学,人工智能与深度学习:《[数理统计](https://ngte-aidl.gitbook.io/i/)》、《[数据分析](https://ngte-aidl.gitbook.io/i/)》、《[机器学习](https://ngte-aidl.gitbook.io/i/)》、《[深度学习](https://ngte-aidl.gitbook.io/i/)》、《[自然语言处理](https://ngte-aidl.gitbook.io/i/)》、《[工具与工程化](https://ngte-aidl.gitbook.io/i/)》、《[行业应用](https://ngte-aidl.gitbook.io/i/)》 49 | 50 | * 产品设计与用户体验:《[产品设计](https://ngte-pd.gitbook.io/i/)》、《[交互体验](https://ngte-pd.gitbook.io/i/)》、《[项目管理](https://ngte-pd.gitbook.io/i/)》 51 | 52 | * 行业应用:《[行业迷思](https://github.com/wx-chevalier/Business-Series)》、《[功能域](https://github.com/wx-chevalier/Business-Series)》、《[电子商务](https://github.com/wx-chevalier/Business-Series)》、《[智能制造](https://github.com/wx-chevalier/Business-Series)》 53 | 54 | 此外,你还可前往 [xCompass](https://wx-chevalier.github.io/home/#/search) 交互式地检索、查找需要的文章/链接/书籍/课程;或者在 [MATRIX 文章与代码索引矩阵](https://github.com/wx-chevalier/Developer-Zero-To-Mastery)中查看文章与项目源代码等更详细的目录导航信息。最后,你也可以关注微信公众号:『**某熊的技术之路**』以获取最新资讯。 55 | -------------------------------------------------------------------------------- /tuning/java/bin/show-duplicate-java-classes: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | ## display duplicate java classes 4 | 5 | __author__ = 'tg123' 6 | 7 | from glob import glob 8 | from os import walk 9 | from zipfile import ZipFile 10 | from os.path import relpath, isdir 11 | from optparse import OptionParser 12 | 13 | 14 | def list_jar_file_under_lib_dirs(libs): 15 | jar_files = set() 16 | for lib in libs: 17 | if isdir(lib): 18 | jar_files |= {f for f in glob(lib + '/*.jar')} 19 | else: 20 | jar_files.add(lib) 21 | return jar_files 22 | 23 | 24 | def list_class_under_jar_file(jar_file): 25 | return {f for f in ZipFile(jar_file).namelist() if f.lower().endswith('.class')} 26 | 27 | 28 | def list_class_under_class_dir(class_dir): 29 | return {relpath(dir_path + "/" + filename, class_dir) 30 | for dir_path, _, file_names in walk(class_dir) 31 | for filename in file_names if filename.lower().endswith('.class')} 32 | 33 | 34 | def expand_2_class_path(jar_files, class_dirs): 35 | java_class_2_class_paths = {} 36 | # list all classes in jar files 37 | for jar_file in jar_files: 38 | for class_file in list_class_under_jar_file(jar_file): 39 | java_class_2_class_paths.setdefault(class_file, set()).add(jar_file) 40 | # list all classes in class dir 41 | for class_dir in class_dirs: 42 | for class_file in list_class_under_class_dir(class_dir): 43 | java_class_2_class_paths.setdefault(class_file, set()).add(class_dir) 44 | 45 | return java_class_2_class_paths, jar_files | set(class_dirs) 46 | 47 | 48 | def find_duplicate_classes(java_class_2_class_paths): 49 | class_path_2_duplicate_classes = {} 50 | 51 | for java_class, class_paths in list(java_class_2_class_paths.items()): 52 | if len(class_paths) > 1: 53 | classes = class_path_2_duplicate_classes.setdefault(frozenset(class_paths), set()) 54 | classes.add(java_class) 55 | 56 | return class_path_2_duplicate_classes 57 | 58 | 59 | def print_class_paths(class_paths): 60 | print() 61 | print("=" * 80) 62 | print("class paths to find:") 63 | print("=" * 80) 64 | for idx, class_path in enumerate(class_paths): 65 | print(("%-3d: %s" % (idx + 1, class_path))) 66 | 67 | 68 | if __name__ == '__main__': 69 | optionParser = OptionParser('usage: %prog ' 70 | '[-c class-dir1 [-c class-dir2] ...] ' 71 | '[lib-dir1|jar-file1 [lib-dir2|jar-file2] ...]') 72 | optionParser.add_option("-c", "--class-dir", dest="class_dirs", default=[], action="append", help="add class dir") 73 | options, libs = optionParser.parse_args() 74 | 75 | if not options.class_dirs and not libs: 76 | libs = ['.'] 77 | 78 | java_class_2_class_paths, class_paths = expand_2_class_path( 79 | list_jar_file_under_lib_dirs(libs), options.class_dirs) 80 | 81 | class_path_2_duplicate_classes = find_duplicate_classes(java_class_2_class_paths) 82 | 83 | if not class_path_2_duplicate_classes: 84 | print("COOL! No duplicate classes found!") 85 | print_class_paths(class_paths) 86 | exit() 87 | 88 | print("Found duplicate classes in below class path:") 89 | for idx, jars in enumerate(class_path_2_duplicate_classes): 90 | print("%-3d(%d@%d): %s" % (idx + 1, len(class_path_2_duplicate_classes[jars]), len(jars), " ".join(jars))) 91 | 92 | print() 93 | print("=" * 80) 94 | print("Duplicate classes detail info:") 95 | print("=" * 80) 96 | for idx, (jars, classes) in enumerate(class_path_2_duplicate_classes.items()): 97 | print("%-3d(%d@%d): %s" % (idx + 1, len(class_path_2_duplicate_classes[jars]), len(jars), " ".join(jars))) 98 | for i, c in enumerate(classes): 99 | print("\t%-3d %s" % (i + 1, c)) 100 | 101 | print_class_paths(class_paths) 102 | exit(1) -------------------------------------------------------------------------------- /tuning/java/bin/greys: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ## start greys debugger 3 | # program : greys 4 | # author : oldmanpushcart@gmail.com 5 | # date : 2015-05-04 6 | # desc : write for july 7 | # version : 1.7.6.4 8 | 9 | base_dir=$(dirname "$(echo "$0" | sed -e '')") 10 | 11 | # define greys's lib 12 | GREYS_LIB_DIR=${base_dir}/lib 13 | 14 | # last update greys version 15 | DEFAULT_VERSION="1.7.6.4" 16 | 17 | # greys remote url 18 | GREYS_REMOTE_URL="http://ompc.oss.aliyuncs.com/greys" 19 | 20 | # update timeout(sec) 21 | SO_TIMEOUT=5 22 | 23 | # define default target ip 24 | DEFAULT_TARGET_IP="127.0.0.1" 25 | 26 | # define default target port 27 | DEFAULT_TARGET_PORT="3658" 28 | 29 | # define JVM's OPS 30 | JVM_OPS=""; 31 | 32 | 33 | # the option to control greys.sh check the permission 34 | OPTION_CHECK_PERMISSION=1 35 | 36 | # the option to control greys.sh attach target jvm 37 | OPTION_ATTACH_JVM=1 38 | 39 | # the option to control greys.sh active greys-console 40 | OPTION_ACTIVE_CONSOLE=1 41 | 42 | # exit shell with err_code 43 | # $1 : err_code 44 | # $2 : err_msg 45 | exit_on_err() 46 | { 47 | [[ ! -z "${2}" ]] && echo "${2}" 1>&2 48 | exit ${1} 49 | } 50 | 51 | 52 | # get with default value 53 | # $1 : target value 54 | # $2 : default value 55 | default() 56 | { 57 | [[ ! -z "${1}" ]] \ 58 | && echo "${1}" \ 59 | || echo "${2}" 60 | } 61 | 62 | 63 | # check greys permission 64 | check_permission() 65 | { 66 | [ ! -w ${HOME} ] \ 67 | && exit_on_err 1 "permission denied, ${HOME} is not writeable." 68 | } 69 | 70 | 71 | # reset greys work environment 72 | # reset some options for env 73 | reset_for_env() 74 | { 75 | # if env don't define the JAVA_HOME, exit 76 | [ -z ${JAVA_HOME} ] && exit_on_err 1 "NO JAVA_HOME ENV" 77 | 78 | # check the jvm version, we need 1.6+ 79 | local JAVA_VERSION=$(${JAVA_HOME}/bin/java -version 2>&1|awk -F '"' '/version/&&$2>"1.5"{print $2}') 80 | [[ ! -x ${JAVA_HOME} || -z ${JAVA_VERSION} ]] && exit_on_err 1 "illegal ENV, please set \$JAVA_HOME to JDK6+" 81 | 82 | # reset BOOT_CLASSPATH 83 | [ -f ${JAVA_HOME}/lib/tools.jar ] && BOOT_CLASSPATH=-Xbootclasspath/a:${JAVA_HOME}/lib/tools.jar 84 | } 85 | 86 | # the usage 87 | usage() 88 | { 89 | echo " 90 | greys usage: 91 | the format was [@IP:PORT] 92 | : the target Java Process ID 93 | [IP] : the target's IP 94 | [PORT] : the target's PORT 95 | 96 | example: 97 | ./greys.sh 98 | ./greys.sh @[IP] 99 | ./greys.sh @[IP:PORT] 100 | " 101 | } 102 | 103 | # parse the argument 104 | parse_arguments() 105 | { 106 | 107 | TARGET_PID=$(echo ${1}|awk '/^[0-9]*@/;/^[^@]+:/{print "@"$1};/^[0-9]+$/'|awk -F "@" '{print $1}'); 108 | TARGET_IP=$(echo ${1}|awk '/^[0-9]*@/;/^[^@]+:/{print "@"$1};/^[0-9]+$/'|awk -F "@|:" '{print $2}'); 109 | TARGET_PORT=$(echo ${1}|awk '/^[0-9]*@/;/^[^@]+:/{print "@"$1};/^[0-9]+$/'|awk -F ":" '{print $2}'); 110 | 111 | # check pid 112 | if [ -z ${TARGET_PID} ];then 113 | # echo "illegal arguments, the is required." 1>&2 114 | # return 1 115 | OPTION_ATTACH_JVM=0 116 | fi 117 | 118 | # reset ${ip} to default if empty 119 | [ -z ${TARGET_IP} ] && TARGET_IP=${DEFAULT_TARGET_IP} 120 | 121 | # reset ${port} to default if empty 122 | [ -z ${TARGET_PORT} ] && TARGET_PORT=${DEFAULT_TARGET_PORT} 123 | 124 | return 0 125 | 126 | } 127 | 128 | 129 | # attach greys to target jvm 130 | # $1 : greys_local_version 131 | attach_jvm() 132 | { 133 | local greys_lib_dir=${GREYS_LIB_DIR}/greys-$DEFAULT_VERSION 134 | 135 | # if [ ${TARGET_IP} = ${DEFAULT_TARGET_IP} ]; then 136 | if [ ! -z ${TARGET_PID} ]; then 137 | ${JAVA_HOME}/bin/java \ 138 | ${BOOT_CLASSPATH} ${JVM_OPTS} \ 139 | -jar ${greys_lib_dir}/greys-core.jar \ 140 | -pid ${TARGET_PID} \ 141 | -target ${TARGET_IP}":"${TARGET_PORT} \ 142 | -core "${greys_lib_dir}/greys-core.jar" \ 143 | -agent "${greys_lib_dir}/greys-agent.jar" 144 | fi 145 | } 146 | 147 | # active console 148 | # $1 : greys_local_version 149 | active_console() 150 | { 151 | 152 | local greys_lib_dir=${GREYS_LIB_DIR}/greys-$DEFAULT_VERSION 153 | 154 | if type ${JAVA_HOME}/bin/java 2>&1 >> /dev/null; then 155 | 156 | # use default console 157 | ${JAVA_HOME}/bin/java \ 158 | -cp ${greys_lib_dir}/greys-core.jar \ 159 | com.github.ompc.greys.core.GreysConsole \ 160 | ${TARGET_IP} \ 161 | ${TARGET_PORT} 162 | 163 | elif type telnet 2>&1 >> /dev/null; then 164 | 165 | # use telnet 166 | telnet ${TARGET_IP} ${TARGET_PORT} 167 | 168 | elif type nc 2>&1 >> /dev/null; then 169 | 170 | # use netcat 171 | nc ${TARGET_IP} ${TARGET_PORT} 172 | 173 | else 174 | 175 | echo "'telnet' or 'nc' is required." 1>&2 176 | return 1 177 | 178 | fi 179 | } 180 | 181 | # the main 182 | main() 183 | { 184 | echo '==========Thanks to https://github.com/oldmanpushcart/greys-anatomy==========' 185 | while getopts "PUJC" ARG 186 | do 187 | case ${ARG} in 188 | P) OPTION_CHECK_PERMISSION=0;; 189 | J) OPTION_ATTACH_JVM=0;; 190 | C) OPTION_ACTIVE_CONSOLE=0;; 191 | ?) usage;exit 1;; 192 | esac 193 | done 194 | 195 | shift $((OPTIND-1)); 196 | 197 | if [[ ${OPTION_CHECK_PERMISSION} -eq 1 ]]; then 198 | check_permission 199 | fi 200 | 201 | reset_for_env 202 | 203 | parse_arguments "${@}" \ 204 | || exit_on_err 1 "$(usage)" 205 | 206 | if [[ ${OPTION_ATTACH_JVM} -eq 1 ]]; then 207 | attach_jvm \ 208 | || exit_on_err 1 "attach to target jvm(${TARGET_PID}) failed." 209 | fi 210 | 211 | if [[ ${OPTION_ACTIVE_CONSOLE} -eq 1 ]]; then 212 | active_console \ 213 | || exit_on_err 1 "active console failed." 214 | fi 215 | } 216 | 217 | main "${@}" 218 | -------------------------------------------------------------------------------- /tuning/java/bin/find-in-jars: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # @Function 3 | ## Find file in the jar files under current directory 4 | # 5 | # @Usage 6 | # $ find-in-jars.sh 'log4j\.properties' 7 | # $ find-in-jars.sh '^log4j(\.properties|\.xml)$' 8 | # $ find-in-jars.sh 'log4j\.properties$' -d /path/to/find/directory 9 | # $ find-in-jars.sh 'log4j\.properties' -d /path/to/find/directory1 -d /path/to/find/directory2 10 | # 11 | # @author Jerry Lee 12 | 13 | readonly PROG=`basename $0` 14 | 15 | usage() { 16 | [ -n "$1" -a "$1" != 0 ] && local out=/dev/stderr || local out=/dev/stdout 17 | 18 | > $out cat <&2 ; usage 1; } 81 | [ "${#args[@]}" -gt 1 ] && { echo "More than 1 file pattern!" 1>&2 ; usage 1; } 82 | readonly pattern="${args[0]}" 83 | 84 | ################################################################################ 85 | # Check the existence of command for listing zip entry! 86 | ################################################################################ 87 | 88 | # `zipinfo -1`/`unzip -Z1` is ~25 times faster than `jar tf`, find zipinfo/unzip command first. 89 | # 90 | # How to list files in a zip without extra information in command line 91 | # https://unix.stackexchange.com/a/128304/136953 92 | if which zipinfo &> /dev/null; then 93 | readonly command_for_list_zip='zipinfo -1' 94 | elif which unzip &> /dev/null; then 95 | readonly command_for_list_zip='unzip -Z1' 96 | else 97 | if ! which jar &> /dev/null; then 98 | [ -z "$JAVA_HOME" ] && { 99 | echo "Error: jar not found on PATH!" 1>&2 100 | exit 1 101 | } 102 | ! [ -f "$JAVA_HOME/bin/jar" ] && { 103 | echo "Error: jar not found on PATH and \$JAVA_HOME/bin/jar($JAVA_HOME/bin/jar) file does NOT exists!" 1>&2 104 | exit 1 105 | } 106 | ! [ -x "$JAVA_HOME/bin/jar" ] && { 107 | echo "Error: jar not found on PATH and \$JAVA_HOME/bin/jar($JAVA_HOME/bin/jar) is NOT executalbe!" 1>&2 108 | exit 1 109 | } 110 | export PATH="$JAVA_HOME/bin:$PATH" 111 | fi 112 | 113 | readonly command_for_list_zip='jar tf' 114 | fi 115 | 116 | ################################################################################ 117 | # find logic 118 | ################################################################################ 119 | 120 | [ -c /dev/stdout ] && readonly is_console=true || readonly is_console=false 121 | 122 | # Getting console width using a bash script 123 | # https://unix.stackexchange.com/questions/299067 124 | $is_console && readonly columns=$(stty size | awk '{print $2}') 125 | 126 | print_responsive_message() { 127 | $is_console || return 128 | 129 | local message="$*" 130 | # http://www.linuxforums.org/forum/red-hat-fedora-linux/142825-how-truncate-string-bash-script.html 131 | echo -n "${message:0:columns}" 132 | } 133 | 134 | clear_responsive_message() { 135 | $is_console || return 136 | 137 | # How to delete line with echo? 138 | # https://unix.stackexchange.com/questions/26576 139 | # 140 | # terminal escapes: http://ascii-table.com/ansi-escape-sequences.php 141 | # In particular, to clear from the cursor position to the beginning of the line: 142 | # echo -e "\033[1K" 143 | # Or everything on the line, regardless of cursor position: 144 | # echo -e "\033[2K" 145 | echo -n -e "\033[2K\\r" 146 | } 147 | 148 | 149 | readonly jar_files="$(find "${dirs[@]}" -iname '*.jar')" 150 | readonly total_count="$(echo "$jar_files" | wc -l)" 151 | [ -z "$jar_files" ] && { 152 | echo "No jar found!" 1>&2 153 | exit 1 154 | } 155 | 156 | counter=1 157 | while read jar_file; do 158 | print_responsive_message "finding in jar($((counter++))/$total_count): $jar_file" 159 | 160 | $command_for_list_zip "${jar_file}" | grep $regex_mode "$pattern" | while read file; do 161 | clear_responsive_message 162 | 163 | echo "${jar_file}"\!"${file}" 164 | done 165 | 166 | clear_responsive_message 167 | 168 | done < <(echo "$jar_files") -------------------------------------------------------------------------------- /tuning/java/bin/vjdump: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ## dump all of the information in running jvm 3 | 4 | echo '==========Thanks to https://github.com/vipshop/vjtools==========' 5 | 6 | USAGE() 7 | { 8 | echo "usage: $0 [--liveheap][-nz|--nozip][-i|--interval] " 9 | } 10 | 11 | if [ $# -lt 1 ]; then 12 | USAGE 13 | exit -1 14 | fi 15 | 16 | BASEDIR=/tmp/vjtools 17 | LOGDIR=${BASEDIR}/vjdump 18 | SLEEP_TIME=1 19 | CLOSE_COMPRESS=0 20 | NEED_HEAP_DUMP=0 21 | PID="$1" 22 | 23 | while true; do 24 | case "$1" in 25 | -i|--interval) SLEEP_TIME="$2"; PID="$3"; shift 1;; 26 | -nz|--nozip) CLOSE_COMPRESS=1; PID="$2"; shift;; 27 | --liveheap) NEED_HEAP_DUMP=1; PID="$2"; shift;; 28 | *) break;; 29 | esac 30 | done 31 | 32 | CMD="$1" 33 | shift 34 | 35 | START() 36 | { 37 | if [[ x"$PID" == x ]]; then 38 | echo -e "The pid is empty, please enter pid". 39 | exit -1 40 | else 41 | echo -e "The pid is ${PID}" 42 | fi 43 | 44 | # clean all history logs 45 | rm -rf ${LOGDIR}/*.log ${LOGDIR}/*jmap_dump_live-*.bin 46 | mkdir -p ${LOGDIR} 47 | 48 | DATE=$(date "+%Y%m%d%H%M%S") 49 | 50 | echo -e "\033[34m$(date '+%Y-%m-%d %H:%M:%S') vjdump begin. command interval is ${SLEEP_TIME}s.\033[0m" 51 | 52 | # jstack 53 | echo -e "$(date '+%Y-%m-%d %H:%M:%S') Begin to process jstack." 54 | JSTACK_LOG=${LOGDIR}/jstack-${PID}-${DATE}.log 55 | jstack -l $PID > ${JSTACK_LOG} 56 | if [[ $? != 0 ]]; then 57 | echo -e "\033[31mprocess jstack error, now exit.\033[0m" 58 | exit -1 59 | fi 60 | echo -e "$(date '+%Y-%m-%d %H:%M:%S') Finish to process jstack." 61 | sleep ${SLEEP_TIME} 62 | 63 | # sjk ttop 64 | PRGDIR=`dirname "$0"` 65 | TOP_SCRIPT=${PRGDIR}/sjk 66 | which $TOP_SCRIPT 2>/dev/null 67 | if [[ $? == 0 ]]; then 68 | TOP_DURATION=3 69 | echo -e "$(date '+%Y-%m-%d %H:%M:%S') Begin to process sjk ttop." 70 | echo -e "It will take ${TOP_DURATION} seconds, please wait." 71 | TOP_LOG=${LOGDIR}/top-${PID}-${DATE}.log 72 | $TOP_SCRIPT ttop -n 1 -ri ${TOP_DURATION}s -p $PID > ${TOP_LOG} 73 | if [[ $? != 0 ]]; then 74 | echo -e "\033[31mprocess top error, now exit.\033[0m" 75 | exit -1 76 | fi 77 | echo -e "$(date '+%Y-%m-%d %H:%M:%S') Finish to process sjk ttop." 78 | fi 79 | 80 | # jmap -histo 81 | echo -e "$(date '+%Y-%m-%d %H:%M:%S') Begin to process jmap -histo." 82 | JMAP_HISTO_LOG=${LOGDIR}/jmap_histo-${PID}-${DATE}.log 83 | jmap -histo $PID > ${JMAP_HISTO_LOG} 84 | if [[ $? != 0 ]]; then 85 | echo -e "\033[31mprocess jmap -histo error, now exit.\033[0m" 86 | exit -1 87 | fi 88 | echo -e "$(date '+%Y-%m-%d %H:%M:%S') Finish to process jmap -histo." 89 | sleep ${SLEEP_TIME} 90 | 91 | # jmap -histo:live 92 | echo -e "$(date '+%Y-%m-%d %H:%M:%S') Begin to process jmap -histo:live." 93 | JMAP_HISTO_LIVE_LOG=${LOGDIR}/jmap_histo_live-${PID}-${DATE}.log 94 | jmap -histo:live $PID > ${JMAP_HISTO_LIVE_LOG} 95 | if [[ $? != 0 ]]; then 96 | echo -e "\033[31mprocess jmap -histo:live error, now exit.\033[0m" 97 | exit -1 98 | fi 99 | echo -e "$(date '+%Y-%m-%d %H:%M:%S') Finish to process jmap -histo:live." 100 | sleep ${SLEEP_TIME} 101 | 102 | # jmap -dump:live 103 | if [[ $NEED_HEAP_DUMP == 1 ]]; then 104 | JMAP_DUMP_FILE=${LOGDIR}/jmap_dump_live-${PID}-${DATE}.bin 105 | echo -e "$(date '+%Y-%m-%d %H:%M:%S') Begin to process jmap -dump:live." 106 | jmap -dump:live,format=b,file=${JMAP_DUMP_FILE} $PID 107 | if [[ $? != 0 ]]; then 108 | echo -e "\033[31mprocess jmap -dump:live error, now exit.\033[0m" 109 | exit -1 110 | fi 111 | echo -e "$(date '+%Y-%m-%d %H:%M:%S') Finish to process jmap -dump:live." 112 | 113 | sleep ${SLEEP_TIME} 114 | fi 115 | 116 | # jinfo -flags $PID 117 | echo -e "$(date '+%Y-%m-%d %H:%M:%S') Begin to process jinfo -flags." 118 | JINFO_FLAGS_LOG=${LOGDIR}/jinfo-flags-${PID}-${DATE}.log 119 | jinfo -flags $PID 1>${JINFO_FLAGS_LOG} 2>&1 120 | if [[ $? != 0 ]]; then 121 | echo -e "\033[31mprocess jinfo -flags error, now exit.\033[0m" 122 | exit -1 123 | fi 124 | echo -e "$(date '+%Y-%m-%d %H:%M:%S') Finish to process jinfo -flags." 125 | 126 | # gc log 127 | echo -e "$(date '+%Y-%m-%d %H:%M:%S') Begin to process gc log." 128 | GCLOG=$(strings /proc/${PID}/cmdline |grep '\-Xloggc' |cut -d : -f 2) 129 | if [[ x"$GCLOG" == x ]]; then 130 | echo -e "No GC log existing." 131 | else 132 | # "\cp" means unalias cp, it can cover files without prompting 133 | \cp -rf $GCLOG ${LOGDIR}/ 134 | if [[ $? != 0 ]]; then 135 | echo -e "copy gc log error, now exit." 136 | exit -1 137 | fi 138 | fi 139 | echo -e "$(date '+%Y-%m-%d %H:%M:%S') Finish to process gc log." 140 | 141 | # packaging 142 | if [[ $CLOSE_COMPRESS == 1 ]]; then 143 | echo -e "The zip option is closed, no zip package will be generated." 144 | else 145 | echo -e "$(date '+%Y-%m-%d %H:%M:%S') Begin to zip all files." 146 | # zip files without heap dump 147 | ZIP_FILE=${BASEDIR}/vjdump-${PID}-${DATE}.zip 148 | zip -j ${ZIP_FILE} ${LOGDIR}/*.log 149 | if [[ $? != 0 ]]; then 150 | echo -e "\033[31mzip files error, exit.\033[0m" 151 | exit -1 152 | else 153 | echo -e "zip files success, the zip file is \033[34m${ZIP_FILE}\033[0m" 154 | fi 155 | echo -e "$(date '+%Y-%m-%d %H:%M:%S') Finish to zip all files." 156 | 157 | if [[ $NEED_HEAP_DUMP == 1 ]]; then 158 | # compress all files 159 | echo -e "$(date '+%Y-%m-%d %H:%M:%S') Begin to zip files which include dump file." 160 | ZIP_FILE_WITH_HEAP_DUMP=${BASEDIR}/vjdump-with-heap-${PID}-${DATE}.zip 161 | zip -j ${ZIP_FILE_WITH_HEAP_DUMP} ${LOGDIR}/*.log ${JMAP_DUMP_FILE} 162 | if [[ $? != 0 ]]; then 163 | echo -e "\033[31mzip files which include dump file error, exit.\033[0m" 164 | exit -1 165 | else 166 | echo -e "zip files which include dump file success, the zip path is \033[34m${ZIP_FILE_WITH_HEAP_DUMP}\033[0m" 167 | fi 168 | echo -e "$(date '+%Y-%m-%d %H:%M:%S') Finish to zip files which include dump file." 169 | fi 170 | fi 171 | echo -e "\033[34m$(date '+%Y-%m-%d %H:%M:%S') vjdump finish. \033[0m" 172 | } 173 | 174 | case "$CMD" in 175 | help) USAGE;; 176 | *) START;; 177 | esac -------------------------------------------------------------------------------- /ops/检测 Apache 与 Nginx 访问峰值.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ## 4 | # 2018 Bobby I. 5 | # Script that summarizes your access logs 6 | # This includes: 7 | # - POST requests 8 | # - GET requests 9 | # - IP logs and their geo location 10 | ## 11 | 12 | ######################## 13 | ### Color Variables ### 14 | ######################## 15 | green='\e[32m' 16 | blue='\e[34m' 17 | clear='\e[0m' 18 | orange='\e[33m' 19 | red='\e[31m' 20 | 21 | ######################### 22 | ### Color Functions ### 23 | ######################### 24 | 25 | ColorGreen(){ 26 | echo -ne $green$1$clear 27 | } 28 | ColorBlue(){ 29 | echo -ne $blue$1$clear 30 | } 31 | ColorRed(){ 32 | echo -ne $red$1$clear 33 | } 34 | ColorOrange(){ 35 | echo -ne $orange$1$clear 36 | } 37 | 38 | ########################################################################### 39 | ## GeoIP domain ## 40 | ## Uses our own GEO location API script to get the country code of an IP ## 41 | ## The connection goes though HTTPS ## 42 | ## To disable the GEO location check set the value to 0 ## 43 | ########################################################################### 44 | 45 | geoipdomain="https://bobbyiliev.com/ip.php" 46 | 47 | ################# 48 | ## Apache logs ## 49 | ################# 50 | 51 | function access_log_summary() { 52 | 53 | # The log is the first argument 54 | log=${1} 55 | if [[ $log ]] ; then 56 | # Check if the log is empty 57 | if [[ $(cat $log 2>/dev/null | wc -l ) -lt 1 ]]; then 58 | echo "" 59 | echo $(ColorOrange " Empty log or does not exist"); 60 | echo $(ColorGreen " Specify the log file that you want to summarize"); 61 | echo $(ColorOrange " Example:"); 62 | echo $(ColorOrange " ./spike_check your_log"); 63 | echo "" 64 | exit 0 65 | fi 66 | 67 | echo "" 68 | echo $(ColorOrange "Summarizing log..") 69 | echo $(ColorOrange "This might take a while depending on the size of the log") 70 | echo "" 71 | echo $(ColorGreen "Top 20 GET requests: ") 72 | sleep 1 73 | cat $log 2>/dev/null | grep -v 'ftp.' | grep GET | cut -d\" -f2 | awk '{print $1 " " $2}' | cut -d? -f1 | sort | uniq -c | sort -n | sed 's/[ ]*//' | tail -20 | sed 's/^ *//g' | column -s '' -s ' ' -t 74 | sleep 1 75 | echo "" 76 | echo $(ColorGreen "Most Recent top 20 GET requests: ") 77 | sleep 1 78 | tail -n 1000 $log 2>/dev/null | grep -v 'ftp.' | grep GET | cut -d\" -f2 | awk '{print $1 " " $2}' | cut -d? -f1 | sort | uniq -c | sort -n | sed 's/[ ]*//' | tail -20 | sed 's/^ *//g' | column -s '' -s ' ' -t 79 | sleep 1 80 | echo "" 81 | echo $(ColorGreen "Top 20 POST requests for: ") 82 | sleep 1 83 | cat $log 2>/dev/null | grep -v 'ftp.' | grep POST | cut -d\" -f2 | awk '{print $1 " " $2}' | cut -d? -f1 | sort | uniq -c | sort -n | sed 's/[ ]*//' | tail -20 | sed 's/^ *//g' | column -s '' -s ' ' -t 84 | sleep 1 85 | echo "" 86 | echo $(ColorGreen "Most Recent top 20 POST requests: ") 87 | sleep 1 88 | tail -n 1000 $log 2>/dev/null | grep -v 'ftp.' | grep POST | cut -d\" -f2 | awk '{print $1 " " $2}' | cut -d? -f1 | sort | uniq -c | sort -n | sed 's/[ ]*//' | tail -20 | sed 's/^ *//g' | column -s '' -s ' ' -t 89 | sleep 1 90 | echo "" 91 | echo $(ColorGreen "Top 20 IP addresses that have been accessing your site: ") 92 | sleep 1 93 | echo "Do you want geo location check for the IPs? [yes/no]" 94 | read geo 95 | if [[ $geo == 'yes' ]] ; then 96 | oIFS="$IFS" 97 | IFS=$'\n' 98 | for ips in $(cat $log 2>/dev/null | awk '{print $1}' |sort | uniq -c | sort -rn | head -20 | sed 's/^ *//g' | column -s '' -s ' ' -t); do 99 | IFS=' ' 100 | array=($ips) 101 | hits="${array[0]}" 102 | ip="${array[1]}" 103 | if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then 104 | location=$(curl ${geoipdomain}?ip=$ip 2>/dev/null) 105 | echo $hits - $ip - $location | sed 's/^ *//g' | column -s '-' -t 106 | fi 107 | unset location 108 | done 109 | IFS="$oIFS" 110 | else 111 | cat $log 2>/dev/null | awk '{print $1}' |sort | uniq -c | sort -rn | head -20 | sed 's/^ *//g' | column -s ' ' -s ' ' -t 112 | fi 113 | echo "" 114 | echo $(ColorGreen "Most Recent top 20 IP addresses: ") 115 | if [[ $geo == "yes" ]] ; then 116 | oIFS="$IFS" 117 | IFS=$'\n' 118 | for ips in $(tail -n 1000 $log 2>/dev/null | awk '{print $1}' |sort | uniq -c | sort -rn | head -20 | sed 's/^ *//g' | column -s '' -s ' ' -t); do 119 | IFS=' ' 120 | array=($ips) 121 | hits="${array[0]}" 122 | ip="${array[1]}" 123 | if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then 124 | location=$(curl ${geoipdomain}?ip=$ip 2>/dev/null) 125 | echo $hits - $ip - $location | sed 's/^ *//g' | column -s '-' -t 126 | fi 127 | unset location 128 | done 129 | IFS="$oIFS" 130 | else 131 | tail -n 1000 $log 2>/dev/null | awk '{print $1}' |sort | uniq -c | sort -rn | head -20 | sed 's/^ *//g' | column -s '' -s ' ' -t 132 | fi 133 | else 134 | echo "" 135 | echo $(ColorGreen "No log found.."); 136 | sleep 1 137 | fi 138 | echo $(ColorRed "########## END log ###########"); 139 | } 140 | 141 | if [[ -z $1 ]] ; then 142 | echo "" 143 | echo $(ColorGreen " This script summarizes your access logs, optimized for Apache"); 144 | echo "" 145 | echo $(ColorGreen " Specify the log that you want to summarize.."); 146 | echo $(ColorOrange " Example:"); 147 | echo $(ColorOrange " ./spike_check your_log"); 148 | echo "" 149 | else 150 | access_log_summary $1 151 | fi -------------------------------------------------------------------------------- /tuning/tpl/run-cmd-tpl.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #chkconfig - 99 1 3 | #pidfile /home/monitor/monitor_agent/agent.pid 4 | 5 | ### BEGIN INIT INFO 6 | # Provides: monitor-agent 7 | # Required-Start: $local_fs $remote_fs $network $syslog 8 | # Required-Stop: $local_fs $remote_fs $network $syslog 9 | # Default-Start: 2 3 4 5 10 | # Default-Stop: 0 1 6 11 | # Short-Description: OM monitor agent. 12 | # Description: OM monitor agent. 13 | ### END INIT INFO 14 | 15 | RES_COL=60 16 | MOVE_TO_COL="echo -en \\033[${RES_COL}G" 17 | SETCOLOR_SUCCESS="echo -en \\033[1;32m" 18 | SETCOLOR_FAILURE="echo -en \\033[1;31m" 19 | SETCOLOR_WARNING="echo -en \\033[1;33m" 20 | SETCOLOR_NORMAL="echo -en \\033[0;39m" 21 | myecho_success() { 22 | $MOVE_TO_COL 23 | echo -n "[" 24 | $SETCOLOR_SUCCESS 25 | echo -n $" OK " 26 | $SETCOLOR_NORMAL 27 | echo -n "]" 28 | echo -ne "\r" 29 | return 0 30 | } 31 | myecho_failure() { 32 | $MOVE_TO_COL 33 | echo -n "[" 34 | $SETCOLOR_FAILURE 35 | echo -n $"FAILED" 36 | $SETCOLOR_NORMAL 37 | echo -n "]" 38 | echo -ne "\r" 39 | return 1 40 | } 41 | myecho_warning() { 42 | $MOVE_TO_COL 43 | echo -n "[" 44 | $SETCOLOR_WARNING 45 | echo -n $"WARNING" 46 | $SETCOLOR_NORMAL 47 | echo -n "]" 48 | echo -ne "\r" 49 | return 1 50 | } 51 | mySuccess(){ 52 | echo -n $* 53 | myecho_success 54 | echo "" 55 | } 56 | myFailure(){ 57 | echo -n $* 58 | myecho_failure 59 | echo "" 60 | } 61 | myWarning(){ 62 | echo -n $* 63 | myecho_warning 64 | echo "" 65 | } 66 | 67 | myCheckpid() { 68 | local i 69 | for i in $* ; do 70 | [ -d "/proc/$i" ] && return 0 71 | done 72 | return 1 73 | } 74 | 75 | 76 | myCheckpidfile(){ 77 | # return 0 process exists 78 | # return 1 file not exists 79 | # return 2 file exists but process not exists 80 | file=$1 81 | if [ ! -f $file ]; then 82 | return 1 83 | fi 84 | local pid=`cat $file` 85 | if [ -z $pid ]; then 86 | return 1 87 | fi 88 | myCheckpid $pid 89 | ret=$? 90 | if [ $ret -eq 0 ]; then 91 | return 0 92 | else 93 | return 2 94 | fi 95 | } 96 | 97 | JAVA_VERSION=1.5 98 | s=`java -version 2>&1`; 99 | i=0; 100 | for e in $s; do 101 | if [ $i -eq 2 ]; then 102 | len=${#e}; 103 | len=$(($len-2)); 104 | JAVA_VERSION=${e:1:3}; 105 | break; 106 | fi; 107 | i=$(($i+1)); 108 | done; 109 | JAVA_COMMAND="java" 110 | if [ "$JAVA_VERSION" \> 1.5 ]; then 111 | JAVA_COMMAND="java"; 112 | echo "JAVA_VERSION:$JAVA_VERSION"; 113 | else 114 | 115 | #debian 116 | FIND=0; 117 | JAVA_TMP_HOME="/usr/lib/jvm/java-6-sun" 118 | if [ -e $JAVA_TMP_HOME -a $FIND -eq 0 ]; then 119 | FIND=1; 120 | JAVA_COMMAND="$JAVA_TMP_HOME/bin/java" 121 | echo "debian JAVA_COMMAND: $JAVA_COMMAND"; 122 | fi 123 | 124 | JAVA_TMP_HOME="/home/monitor/jdk1.6.0_29" 125 | if [ -d $JAVA_TMP_HOME -a $FIND -eq 0 ]; then 126 | FIND=1; 127 | JAVA_COMMAND="$JAVA_TMP_HOME/bin/java" 128 | echo "JAVA_COMMAND: $JAVA_COMMAND"; 129 | fi 130 | 131 | #redhat 132 | JAVA_TMP_HOME="/usr/java/latest" 133 | if [ -e $JAVA_TMP_HOME -a $FIND -eq 0 ]; then 134 | FIND=1; 135 | JAVA_COMMAND="$JAVA_TMP_HOME/bin/java" 136 | echo "redhat JAVA_COMMAND: $JAVA_COMMAND"; 137 | fi 138 | 139 | if [ ! -x $JAVA_COMMAND ]; then 140 | echo "$JAVA_COMMAND is not a excutable command!" 141 | exit 1 142 | fi 143 | fi 144 | 145 | shellfile=$0 146 | while [ -L $shellfile ]; do 147 | shellfile=`readlink -f $shellfile` 148 | if [ ! -e $shellfile ]; then 149 | echo "$shellfile not exits!" 150 | exit 1 151 | fi 152 | done 153 | 154 | # 155 | BASE_HOME=$(cd "$(dirname "$shellfile")"; pwd) 156 | if [ ! -d $BASE_HOME ]; then 157 | echo "$BASE_HOME is not a directory!" 158 | exit 1 159 | fi 160 | 161 | # 162 | PID_FILE="/var/lock/sw_monitor.pid" 163 | MONITOR_JAR="$BASE_HOME/sw_monitor.jar" 164 | JARS=`ls $BASE_HOME/*.jar` 165 | for jar in $JARS; do 166 | MONITOR_JAR=$jar 167 | done 168 | 169 | MONITOR_APPNAME="SwitchMonitor" 170 | #-Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000 -Dcom.sun.management.jmxremote.port=9312 171 | OPTS="-server -jar -Xmx64m -Xms32m -Dcom.xx.appname=$MONITOR_APPNAME" 172 | COMMAND="$JAVA_COMMAND $OPTS $MONITOR_JAR" 173 | STOP_COMMAND="kill -9" 174 | NAME="OM Switch Monitor" 175 | 176 | cd "$BASE_HOME"; 177 | echo "BASE_HOME:"`pwd`; 178 | echo ""; 179 | 180 | start(){ 181 | echo $COMMAND 182 | echo -n "start to run $NAME" 183 | myCheckpidfile $PID_FILE 184 | ret=$? 185 | if [ $ret -eq 0 ]; then 186 | echo "" 187 | myWarning "$NAME already exists!" 188 | return 0; 189 | elif [ $ret -eq 1 ] || [ $ret -eq 2 ]; then 190 | $COMMAND > /dev/null 2>&1 & 191 | pid=$! 192 | sleep 2 193 | myCheckpid $pid 194 | ret=$? 195 | if [ $ret -eq 1 ]; then 196 | myFailure 197 | return 1 198 | else 199 | mySuccess 200 | echo "$pid" > $PID_FILE 201 | chmod 666 $PID_FILE > /dev/null 2>&1 || "" 202 | return 0 203 | fi 204 | fi 205 | } 206 | 207 | stop(){ 208 | echo -n "stopping $NAME" 209 | myCheckpidfile $PID_FILE 210 | ret=$? 211 | if [ $ret -eq 0 ]; then 212 | pid=`cat $PID_FILE` 213 | $STOP_COMMAND $pid >/dev/null 214 | sleep 2 215 | myCheckpid $pid 216 | ret=$? 217 | if [ $ret -eq 1 ]; then 218 | mySuccess 219 | rm -rf $PID_FILE > /dev/null 2>&1 || "" 220 | return 0 221 | else 222 | myFailure 223 | return 1 224 | fi 225 | elif [ $ret -eq 1 ]; then 226 | echo "" 227 | myWarning "$NAME not run" 228 | return 1 229 | else 230 | echo "" 231 | myWarning "$NAME pid file exists but not run" 232 | return 1 233 | fi 234 | } 235 | 236 | status(){ 237 | myCheckpidfile $PID_FILE 238 | ret=$? 239 | if [ $ret -eq 0 ]; then 240 | pid=`cat $PID_FILE` 241 | mySuccess "$NAME is running with pid=$pid" 242 | exit 0 243 | elif [ $ret -eq 1 ]; then 244 | echo "" 245 | mySuccess "$NAME is not running" 246 | exit 1 247 | else 248 | myWarning "$NAME is not running but pid file exists" 249 | exit 2 250 | fi 251 | } 252 | 253 | restart(){ 254 | stop 255 | start 256 | return 0 257 | } 258 | 259 | case $1 in 260 | start) 261 | start 262 | ;; 263 | stop) 264 | stop 265 | ;; 266 | status) 267 | status 268 | ;; 269 | restart) 270 | restart 271 | ;; 272 | *) 273 | echo "Usage $0 start|stop|restart|status|dellog" 274 | exit 1; 275 | ;; 276 | esac 277 | -------------------------------------------------------------------------------- /tuning/test-cases/parseOpts-test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BASE=`dirname $0` 4 | 5 | . $BASE/../parseOpts.sh 6 | 7 | 8 | ################################################# 9 | # Utils Methods 10 | ################################################# 11 | 12 | colorEcho() { 13 | local color=$1 14 | shift 15 | if [ -c /dev/stdout ] ; then 16 | # if stdout is console, turn on color output. 17 | echo -ne "\033[1;${color}m" 18 | echo -n "$@" 19 | echo -e "\033[0m" 20 | else 21 | echo "$@" 22 | fi 23 | } 24 | 25 | redEcho() { 26 | colorEcho 31 "$@" 27 | } 28 | 29 | greenEcho() { 30 | colorEcho 32 "$@" 31 | } 32 | 33 | yellowEcho() { 34 | colorEcho 33 "$@" 35 | } 36 | 37 | blueEcho() { 38 | colorEcho 34 "$@" 39 | } 40 | 41 | arrayEquals() { 42 | local a1PlaceHolder="$1[@]" 43 | local a2PlaceHolder="$2[@]" 44 | local a1=("${!a1PlaceHolder}") 45 | local a2=("${!a2PlaceHolder}") 46 | 47 | [ ${#a1[@]} -eq ${#a2[@]} ] || return 1 48 | 49 | local i 50 | for((i=0; i<${#a1[@]}; i++)); do 51 | [ "${a1[$i]}" = "${a2[$i]}" ] || return 1 52 | done 53 | } 54 | 55 | compareAllVars() { 56 | local test_afterVars=`declare` 57 | diff <(echo "$test_beforeVars" | grep -v '^BASH_\|^_=') <(echo "$test_afterVars" | grep -v '^BASH_\|^_=\|^FUNCNAME=\|^test_') 58 | } 59 | 60 | compareAllVarsExcludeOptVars() { 61 | local test_afterVars=`declare` 62 | diff <(echo "$test_beforeVars" | grep -v '^BASH_\|^_=') <(echo "$test_afterVars" | grep -v '^BASH_\|^_=\|^FUNCNAME=\|^test_\|^_OPT_\|^_opts_index_name_') 63 | } 64 | 65 | fail() { 66 | redEcho "TEST FAIL: $@" 67 | exit 1 68 | } 69 | 70 | ################################################# 71 | # Test 72 | ################################################# 73 | 74 | test_beforeVars=`declare` 75 | 76 | # ======================================== 77 | blueEcho "Test case: success parse" 78 | # ======================================== 79 | 80 | parseOpts "a,a-long|b,b-long:|c,c-long+|d,d-long+" aa -a -b bb -c c.sh -p pv -q qv cc \; bb --d-long d.sh -x xv d1 d2 d3 \; cc dd ee 81 | test_exitCode=$? 82 | _opts_showOptDescInfoList 83 | _opts_showOptValueInfoList 84 | 85 | [ $test_exitCode -eq 0 ] || fail "Wrong exit code!" 86 | [ ${#_OPT_INFO_LIST_INDEX[@]} -eq 4 ] || fail "Wrong _OPT_INFO_LIST_INDEX!" 87 | [ $_OPT_VALUE_a = "true" ] && [ $_OPT_VALUE_a_long = "true" ] || fail "Wrong option value of a!" 88 | [ $_OPT_VALUE_b = "bb" ] && [ $_OPT_VALUE_b_long = "bb" ] || fail "Wrong option value of b!" 89 | test_cArray=(c.sh -p pv -q qv cc) 90 | arrayEquals test_cArray _OPT_VALUE_c && arrayEquals test_cArray _OPT_VALUE_c_long || fail "Wrong option value of c!" 91 | test_dArray=(d.sh -x xv d1 d2 d3 ) 92 | arrayEquals test_dArray _OPT_VALUE_d && arrayEquals test_dArray _OPT_VALUE_d_long || fail "Wrong option value of d!" 93 | test_argArray=(aa bb cc dd ee) 94 | arrayEquals test_argArray _OPT_ARGS || fail "Wrong args!" 95 | 96 | compareAllVarsExcludeOptVars || fail "Unpected extra glable vars!" 97 | _opts_cleanOptValueInfoList 98 | compareAllVars || fail "Unpected extra glable vars!" 99 | 100 | # ======================================== 101 | blueEcho "Test case: success parse with -- " 102 | # ======================================== 103 | 104 | parseOpts "a,a-long|b,b-long:|c,c-long+|d,d-long+" aa -a -b bb -c c.sh -p pv -q qv cc \; bb -- --d-long d.sh -x xv d1 d2 d3 \; cc dd ee 105 | test_exitCode=$? 106 | _opts_showOptDescInfoList 107 | _opts_showOptValueInfoList 108 | 109 | [ $test_exitCode -eq 0 ] || fail "Wrong exit code!" 110 | [ ${#_OPT_INFO_LIST_INDEX[@]} -eq 4 ] || fail "Wrong _OPT_INFO_LIST_INDEX!" 111 | [ $_OPT_VALUE_a = "true" ] && [ $_OPT_VALUE_a_long = "true" ] || fail "Wrong option value of a!" 112 | [ $_OPT_VALUE_b = "bb" ] && [ $_OPT_VALUE_b_long = "bb" ] || fail "Wrong option value of b!" 113 | test_cArray=(c.sh -p pv -q qv cc) 114 | arrayEquals test_cArray _OPT_VALUE_c && arrayEquals test_cArray _OPT_VALUE_c_long || fail "Wrong option value of c!" 115 | [ "$_OPT_VALUE_d" = "" ] && [ "$_OPT_VALUE_d_long" = "" ] || fail "Wrong option value of d!" 116 | test_argArray=(aa bb --d-long d.sh -x xv d1 d2 d3 \; cc dd ee) 117 | arrayEquals test_argArray _OPT_ARGS || fail "Wrong args!" 118 | 119 | compareAllVarsExcludeOptVars || fail "Unpected extra glable vars!" 120 | _opts_cleanOptValueInfoList 121 | compareAllVars || fail "Unpected extra glable vars!" 122 | 123 | 124 | # ======================================== 125 | blueEcho "Test case: illegal option x" 126 | # ======================================== 127 | 128 | parseOpts "a,a-long|b,b-long:|c,c-long+|d,d-long+" aa -a -b bb -x -c c.sh -p pv -q qv cc \; bb --d-long d.sh -x xv d1 d2 d3 \; cc -- dd ee 129 | test_exitCode=$? 130 | _opts_showOptDescInfoList 131 | _opts_showOptValueInfoList 132 | 133 | [ $test_exitCode -eq 232 ] || fail "Wrong exit code!" 134 | [ ${#_OPT_INFO_LIST_INDEX[@]} -eq 0 ] || fail "Wrong _OPT_INFO_LIST_INDEX!" 135 | [ "$_OPT_VALUE_a" = "" ] && [ "$_OPT_VALUE_a_long" = "" ] || fail "Wrong option value of a!" 136 | [ "$_OPT_VALUE_b" = "" ] && [ "$_OPT_VALUE_b_long" = "" ] || fail "Wrong option value of b!" 137 | [ "$_OPT_VALUE_c" = "" ] && [ "$_OPT_VALUE_c_long" = "" ] || fail "Wrong option value of c!" 138 | [ "$_OPT_VALUE_d" = "" ] && [ "$_OPT_VALUE_d_long" = "" ] || fail "Wrong option value of d!" 139 | [ "$_OPT_ARGS" = "" ] || fail "Wrong args!" 140 | 141 | 142 | 143 | # ======================================== 144 | blueEcho "Test case: empty options" 145 | # ======================================== 146 | 147 | parseOpts "a,a-long|b,b-long:|c,c-long+|d,d-long+" 148 | test_exitCode=$? 149 | _opts_showOptDescInfoList 150 | _opts_showOptValueInfoList 151 | 152 | [ $test_exitCode -eq 0 ] || fail "Wrong exit code!" 153 | [ ${#_OPT_INFO_LIST_INDEX[@]} -eq 4 ] || fail "Wrong _OPT_INFO_LIST_INDEX!" 154 | [ "$_OPT_VALUE_a" = "" ] && [ "$_OPT_VALUE_a_long" = "" ] || fail "Wrong option value of a!" 155 | [ "$_OPT_VALUE_b" = "" ] && [ "$_OPT_VALUE_b_long" = "" ] || fail "Wrong option value of b!" 156 | [ "$_OPT_VALUE_c" = "" ] && [ "$_OPT_VALUE_c_long" = "" ] || fail "Wrong option value of c!" 157 | [ "$_OPT_VALUE_d" = "" ] && [ "$_OPT_VALUE_d_long" = "" ] || fail "Wrong option value of d!" 158 | [ "$_OPT_ARGS" = "" ] || fail "Wrong args!" 159 | 160 | 161 | 162 | # ======================================== 163 | blueEcho "Test case: illegal option name" 164 | # ======================================== 165 | 166 | parseOpts "a,a-long|b,b-long:|c,c-long+|d,d-long+|#,z-long" aa -a -b bb -x -c c.sh -p pv -q qv cc \; bb -d d.sh -x xv d1 d2 d3 \; cc -- dd ee 167 | test_exitCode=$? 168 | _opts_showOptDescInfoList 169 | _opts_showOptValueInfoList 170 | 171 | [ $test_exitCode -eq 221 ] || fail "Wrong exit code!" 172 | [ ${#_OPT_INFO_LIST_INDEX[@]} -eq 0 ] || fail "Wrong _OPT_INFO_LIST_INDEX!" 173 | [ "$_OPT_VALUE_a" = "" ] && [ "$_OPT_VALUE_a_long" = "" ] || fail "Wrong option value of a!" 174 | [ "$_OPT_VALUE_b" = "" ] && [ "$_OPT_VALUE_b_long" = "" ] || fail "Wrong option value of b!" 175 | [ "$_OPT_VALUE_c" = "" ] && [ "$_OPT_VALUE_c_long" = "" ] || fail "Wrong option value of c!" 176 | [ "$_OPT_VALUE_d" = "" ] && [ "$_OPT_VALUE_d_long" = "" ] || fail "Wrong option value of d!" 177 | [ "$_OPT_ARGS" = "" ] || fail "Wrong args!" 178 | 179 | 180 | parseOpts "a,a-long|b,b-long:|c,c-long+|d,d-long+|z,z-#long" aa -a -b bb -x -c c.sh -p pv -q qv cc \; bb -d d.sh -x xv d1 d2 d3 \; cc -- dd ee 181 | test_exitCode=$? 182 | _opts_showOptDescInfoList 183 | _opts_showOptValueInfoList 184 | 185 | [ $test_exitCode -eq 222 ] || fail "Wrong exit code!" 186 | [ ${#_OPT_INFO_LIST_INDEX[@]} -eq 0 ] || fail "Wrong _OPT_INFO_LIST_INDEX!" 187 | [ "$_OPT_VALUE_a" = "" ] && [ "$_OPT_VALUE_a_long" = "" ] || fail "Wrong option value of a!" 188 | [ "$_OPT_VALUE_b" = "" ] && [ "$_OPT_VALUE_b_long" = "" ] || fail "Wrong option value of b!" 189 | [ "$_OPT_VALUE_c" = "" ] && [ "$_OPT_VALUE_c_long" = "" ] || fail "Wrong option value of c!" 190 | [ "$_OPT_VALUE_d" = "" ] && [ "$_OPT_VALUE_d_long" = "" ] || fail "Wrong option value of d!" 191 | [ "$_OPT_ARGS" = "" ] || fail "Wrong args!" 192 | 193 | compareAllVars || fail "Unpected extra glable vars!" 194 | 195 | greenEcho "TEST SUCCESS!!!" 196 | -------------------------------------------------------------------------------- /tuning/README.md: -------------------------------------------------------------------------------- 1 | # tuning 2 | 3 | 本项目 fork 自,现已经用于公司运维环境中,基于原项目所做更新如下: 4 | 5 | - 自安装脚本的修改:[self-installer.sh](self-installer.sh) 6 | - Linux 守护进程模板: [tpl/run-cmd-tpl](tpl/run-cmd-tpl) 7 | - 增加脚本统一入口:[opscripts](opscripts) 8 | - 集成开源 java 运维工具脚本:housemd、greys、sjk、jtop 等 9 | - 部分脚本的编写 10 | 11 | --- 12 | 13 | ## 运行/安装环境 14 | 15 | - Linux 16 | - git1.7+ 17 | 18 | ## 安装 19 | 20 | 三种方法 21 | 22 | - `curl -s "https://raw.githubusercontent.com/superhj1987/awesome-scripts/master/self-installer.sh" | bash -s` 23 | - git/svn checkout the source and `make install` 24 | - git/svn checkout the source and set `bin` to the System Path to use the common usage shells 25 | 26 | 此外,可以下载和运行单个文件,以[`show-busy-java-threads`](https://raw.githubusercontent.com/superhj1987/awesome-scripts/master/java/bin/show-busy-java-threads)为例。 27 | 28 | - 直接运行: 29 | 30 | ``` 31 | curl -sLk 'https://raw.githubusercontent.com/superhj1987/awesome-scripts/master/java/bin/show-busy-java-threads' | bash 32 | ``` 33 | 34 | - 下载单个文件 35 | 36 | ``` 37 | wget --no-check-certificate https://raw.githubusercontent.com/superhj1987/awesome-scripts/master/java/bin/show-busy-java-threads 38 | 39 | chmod +x show-busy-java-threads 40 | 41 | ./show-busy-java-threads 42 | ``` 43 | 44 | ## 卸载 45 | 46 | opscripts uninstall 47 | 48 | ## 使用 49 | 50 | - `opscripts` 51 | 52 | > show system command 53 | 54 | - `opscripts list` 55 | 56 | > show command list 57 | 58 | - `opscripts update` 59 | > update opscripts 60 | 61 | ## 命令列表及文档 62 | 63 | ### :coffee: [`Java`相关脚本](docs/java.md) 64 | 65 | 1. [show-busy-java-threads](docs/java.md#beer-show-busy-java-threads) 66 | 67 | > 用于快速排查`Java`的`CPU`性能问题(`top us`值过高),自动查出运行的`Java`进程中消耗`CPU`多的线程,并打印出其线程栈,从而确定导致性能问题的方法调用。 68 | 69 | 2. [show-duplicate-java-classes](docs/java.md#beer-show-duplicate-java-classes) 70 | 71 | > 找出`jar`文件和`class`目录中的重复类。用于排查`Java`类冲突问题。 72 | 73 | 3. [find-in-jars](docs/java.md#beer-find-in-jars) 74 | 75 | > 在目录下所有`jar`文件里,查找类或资源文件。 76 | 77 | 4. [housemd](java/bin/housemd) 78 | 79 | `housemd [pid] [java_home]` 80 | 81 | > 使用 housemd 对 java 程序进行运行时跟踪,支持的操作有: 82 | > 83 | > - 查看加载类 84 | > - 跟踪方法 85 | > - 查看环境变量 86 | > - 查看对象属性值 87 | > - 详细信息请参考: https://github.com/CSUG/HouseMD/wiki/UserGuideCN 88 | 89 | 5. [jargrep](java/bin/jargrep) 90 | 91 | `jargrep "text" [path or jarfile]` 92 | 93 | > 在 jar 包中查找文本,可查找常量字符串、类引用。 94 | 95 | 6. [findcycle](java/bin/findcycle) 96 | 97 | `findcycle [path]` 98 | 99 | > 查找当前工程中是否存在循环引用(目前仅支持 maven 工程,默认为当前路径) 100 | 101 | 7. [jvm](java/bin/jvm) 102 | 103 | `jvm [pid]` 104 | 105 | > 执行jvm debug工具,包含对java栈、堆、线程、gc等状态的查看,支持的功能有: 106 | >
107 |         	>========线程相关=======
108 | 
109 |     > 1 : 查看占用 cpu 最高的线程情况
110 |     > 2 : 打印所有线程
111 |     > 3 : 打印线程数
112 |     > 4 : 按线程状态统计线程数
113 |     > ========GC 相关=======
114 |     > 5 : 垃圾收集统计(包含原因)可以指定间隔时间及执行次数,默认 1 秒, 10 次
115 |     > 6 : 显示堆中各代的空间可以指定间隔时间及执行次数,默认 1 秒,5 次
116 |     > 7 : 垃圾收集统计。可以指定间隔时间及执行次数,默认 1 秒, 10 次
117 |     > 8 : 打印 perm 区内存情况*会使程序暂停响应*
118 |     > 9 : 查看 directbuffer 情况
119 |     > ========堆对象相关=======
120 |     > 10 : dump heap 到文件*会使程序暂停响应*默认保存到`pwd`/dump.bin,可指定其它路径
121 |     > 11 : 触发 full gc。_会使程序暂停响应_
122 |     > 12 : 打印 jvm heap 统计*会使程序暂停响应*
123 |     > 13 : 打印 jvm heap 中 top20 的对象。*会使程序暂停响应*参数:1:按实例数量排序,2:按内存占用排序,默认为 1
124 |     > 14 : 触发 full gc 后打印 jvm heap 中 top20 的对象。*会使程序暂停响应*参数:1:按实例数量排序,2:按内存占用排序,默认为 1
125 |     > 15 : 输出所有类装载器在 perm 里产生的对象。可以指定间隔时间及执行次数
126 |     > ========其它=======
127 |     > 16 : 打印 finalzer 队列情况
128 |     > 17 : 显示 classloader 统计
129 |     > 18 : 显示 jit 编译统计
130 |     > 19 : 死锁检测
131 |     > 20 : 等待 X 秒,默认为 1
132 |     > q : exit
133 |     >
134 |     > 
135 | > 进入jvm工具后可以输入序号执行对应命令 136 | > 可以一次执行多个命令,用分号";"分隔,如:1;3;4;5;6 137 | > 每个命令可以带参数,用冒号":"分隔,同一命令的参数之间用逗号分隔,如: 138 | > Enter command queue:1;5:1000,100;10:/data1/output.bin 139 | 140 | 8. [greys](java/bin/greys) 141 | 142 | `greys [pid][@ip:port]` 143 | 144 | > 使用 greys 对 java 程序进行运行时跟踪(不传参数,需要先`greys -C pid`,再 greys)。支持的操作有: 145 | > 146 | > - 查看加载类,方法信息 147 | > - 查看 JVM 当前基础信息 148 | > - 方法执行监控(调用量,失败率,响应时间等) 149 | > - 方法执行数据观测、记录与回放(参数,返回结果,异常信息等) 150 | > - 方法调用追踪渲染 151 | > - 详细信息请参考: https://github.com/oldmanpushcart/greys-anatomy/wiki 152 | 153 | 9. [sjk](java/bin/sjk) 154 | 155 | `sjk [cmd] [arguments]` 156 | 157 | `sjk --commands` 158 | 159 | `sjk --help [cmd]` 160 | 161 | > 使用 sjk 对 Java 诊断、性能排查、优化工具 162 | > 163 | > - ttop:监控指定 jvm 进程的各个线程的 cpu 使用情况 164 | > - jps: 强化版 165 | > - hh: jmap -histo 强化版 166 | > - gc: 实时报告垃圾回收信息 167 | > - mx: 操作 MBean 168 | > - 更多信息请参考: https://github.com/aragozin/jvm-tools 169 | 170 | 10. [vjmap](java/bin/vjmap) 171 | 172 | `vjmap -all [pid] > /tmp/histo.log` 173 | 174 | `vjmap -old [pid] > /tmp/histo-old.lo` 175 | 176 | `vjmap -sur [pid] > /tmp/histo-sur.log` 177 | 178 | > 使用唯品会的 vjmap(思路来自于阿里巴巴的 TBJMap)查看堆内存的分代占用信息,加强版 jmap 179 | > 180 | > 注意:vjmap 在执行过程中,会完全停止应用一段时间,必须摘流量执行!!!! 181 | > 182 | > 更多信息请参考: https://github.com/vipshop/vjtools/tree/master/vjmap 183 | 184 | 11. [vjdump](java/bin/vjdump) 185 | 186 | `vjdump [pid]` 187 | 188 | `vjdump --liveheap [pid]` 189 | 190 | > 使用唯品会的 vjdump 一次性快速 dump 现场信息,包括: 191 | > 192 | > - JVM 启动参数及命令行参数: jinfo -flags [pid] 193 | > - thread dump 数据:jstack -l [pid] 194 | > - sjk ttop JVM 概况及繁忙线程:sjk ttop -n 1 -ri 3 -p [pid] 195 | > - jmap histo 堆对象统计数据:jmap -histo [pid] & jmap -histo:live [pid] 196 | > - GC 日志(如果 JVM 有设定 GC 日志输出) 197 | > - heap dump 数据(需指定--liveheap 开启):jmap -dump:live,format=b,file=[DUMP_FILE][pid] 198 | > 199 | > 更多信息请参考: https://github.com/vipshop/vjtools/tree/master/vjdump 200 | 201 | 12. [vjmxcli](java/bin/vjmxcli) 202 | 203 | `vjmxcli - [host:port] java.lang:type=Memory HeapMemoryUsage` 204 | 205 | `vjmxcli - [pid] gcutil [interval]` 206 | 207 | > 使用唯品会的 vjmxcli 获取 MBean 属性值以及在 jstat 无法使用时模拟 jstat -gcutil。开启 jmx 时可以使用主机:端口号;未开启 jmx 则使用 pid。 208 | > 209 | > 更多信息请参考: https://github.com/vipshop/vjtools/tree/master/vjmxcli 210 | 211 | ### :shell: [`Shell`相关脚本](docs/shell.md) 212 | 213 | 1. [c](docs/shell.md#beer-c) 214 | 215 | > 原样命令行输出,并拷贝标准输出到系统剪贴板,省去`CTRL+C`操作,优化命令行与其它应用之间的操作流。 216 | 217 | 1. [colines](docs/shell.md#beer-colines) 218 | 219 | > 彩色`cat`出文件行,方便人眼区分不同的行。 220 | 221 | 1. [a2l](docs/shell.md#beer-a2l) 222 | 223 | > 按行彩色输出参数,方便人眼查看。 224 | 225 | 1. [ap & rp](docs/shell.md#beer-ap-and-rp) 226 | 227 | > 批量转换文件路径为绝对路径/相对路径,会自动跟踪链接并规范化路径。 228 | 229 | 1. [echo-args](docs/shell.md#beer-echo-args) 230 | 231 | > 输出脚本收到的参数,在控制台运行时,把参数值括起的括号显示成 **红色**,方便人眼查看。用于调试脚本参数输入。 232 | 233 | 1. [console-text-color-themes](docs/shell.md#beer-console-text-color-themes) 234 | 235 | > 显示`Terminator`的全部文字彩色组合的效果及其打印方式。 236 | 237 | 1. [tcp-connection-state-counter](docs/shell.md#beer-tcp-connection-state-counter) 238 | 239 | > 统计各个`TCP`连接状态的个数。用于方便排查系统连接负荷问题。 240 | 241 | 1. [parseOpts](docs/shell.md#beer-parseopts) 242 | 243 | > 命令行选项解析库,加强支持选项有多个值(即数组)。 244 | 245 | 1. [xpl and xpf](docs/shell.md#beer-xpl-and-xpf) 246 | 247 | > 在命令行中快速完成 在文件浏览器中 打开/选中 指定的文件或文件夹的操作,优化命令行与其它应用之间的操作流。 248 | 249 | 1. [show-cpu-and-memory](docs/shell.md#beer-show-cpu-and-memory) 250 | 251 | > 显示当前 cpu 和内存使用状况,包括全局和各个进程的。 252 | 253 | 1. [monitor-host](docs/shell.md#beer-monitor-host) 254 | 255 | > 监控当前的内存、cpu、io 以及网络状况,写入相应的 log 文件,建议使用 crontab,定时调用此脚本。 256 | 257 | 1. [check-vm](docs/shell.md#beer-check-vmpy) 258 | 259 | > 检查当前 linux 是否是在虚拟机上,包括 openvz/xen、pv/uml、VmWare。 260 | 261 | 1. [get-pip](docs/shell.md#beer-get-pippy) 262 | 263 | > 安装 pip, 将 pip 程序封装在了文件中,可以避免网络安装 pip 过慢。 264 | 265 | 1. [redis](bin/redis) 266 | 267 | `redis ip1[:port1][,ip2[:port2]] [port] "command"` 268 | 269 | > 批量执行 redis 命令(需要 redis-cli) 270 | 271 | 1. [send](bin/send) 272 | 273 | `send filename [port]` 274 | 275 | > 使用 nc 发送文件(默认 8888 端口),接收方可以通过浏览器下载 276 | 277 | 1. [hex](bin/hex) 278 | 279 | `hex [[0x]number[b]]` 280 | 281 | > 计算数字的 10 进制、16 进制及 2 进制文本,输入参数默认为 10 进制,可选 16 进制(0x)及二进制(b)。 282 | 283 | 1. [swap](bin/swap) 284 | 285 | `sudo swap [-s [-r]] [-g GREP_ARG]` 286 | 287 | > 查询当前服务器各个进程占用 swap 的情况。 288 | > -s 表示对 swap 占用量进行排序(升序) -r 表示对 swap 占用量进行排序(降序),使用-r 的前提是-s 参数开启。 -g grep 命令的封装,用于查找特定类型的进程。比如我想查找带有 java 的进程,可以使用 sudo swap -g java 289 | > 290 | > 使用该功能需要 sudo 权限 291 | 292 | 1. [tpl/run-cmd-tpl.sh](docs/shell.md#beer-tplrun-cmd-tplsh) 293 | 294 | > linux 下后台执行守护程序的模板 shell 脚本,修改文件中几个选项的值为需要执行的程序即可使用。 295 | 296 | ### :watch: [`VCS`相关脚本](docs/vcs.md) 297 | 298 | 目前`VCS`的脚本都是`svn`分支相关的操作。使用更现代的`Git`吧! :boom: 299 | 300 | 因为不推荐使用`svn`,这里不再列出有哪些脚本了,如果你有兴趣可以点上面链接去看。 301 | -------------------------------------------------------------------------------- /tuning/LICENSE: -------------------------------------------------------------------------------- 1 | 2 | 3 | Apache License 4 | Version 2.0, January 2004 5 | http://www.apache.org/licenses/ 6 | 7 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 8 | 9 | 1. Definitions. 10 | 11 | "License" shall mean the terms and conditions for use, reproduction, 12 | and distribution as defined by Sections 1 through 9 of this document. 13 | 14 | "Licensor" shall mean the copyright owner or entity authorized by 15 | the copyright owner that is granting the License. 16 | 17 | "Legal Entity" shall mean the union of the acting entity and all 18 | other entities that control, are controlled by, or are under common 19 | control with that entity. For the purposes of this definition, 20 | "control" means (i) the power, direct or indirect, to cause the 21 | direction or management of such entity, whether by contract or 22 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 23 | outstanding shares, or (iii) beneficial ownership of such entity. 24 | 25 | "You" (or "Your") shall mean an individual or Legal Entity 26 | exercising permissions granted by this License. 27 | 28 | "Source" form shall mean the preferred form for making modifications, 29 | including but not limited to software source code, documentation 30 | source, and configuration files. 31 | 32 | "Object" form shall mean any form resulting from mechanical 33 | transformation or translation of a Source form, including but 34 | not limited to compiled object code, generated documentation, 35 | and conversions to other media types. 36 | 37 | "Work" shall mean the work of authorship, whether in Source or 38 | Object form, made available under the License, as indicated by a 39 | copyright notice that is included in or attached to the work 40 | (an example is provided in the Appendix below). 41 | 42 | "Derivative Works" shall mean any work, whether in Source or Object 43 | form, that is based on (or derived from) the Work and for which the 44 | editorial revisions, annotations, elaborations, or other modifications 45 | represent, as a whole, an original work of authorship. For the purposes 46 | of this License, Derivative Works shall not include works that remain 47 | separable from, or merely link (or bind by name) to the interfaces of, 48 | the Work and Derivative Works thereof. 49 | 50 | "Contribution" shall mean any work of authorship, including 51 | the original version of the Work and any modifications or additions 52 | to that Work or Derivative Works thereof, that is intentionally 53 | submitted to Licensor for inclusion in the Work by the copyright owner 54 | or by an individual or Legal Entity authorized to submit on behalf of 55 | the copyright owner. For the purposes of this definition, "submitted" 56 | means any form of electronic, verbal, or written communication sent 57 | to the Licensor or its representatives, including but not limited to 58 | communication on electronic mailing lists, source code control systems, 59 | and issue tracking systems that are managed by, or on behalf of, the 60 | Licensor for the purpose of discussing and improving the Work, but 61 | excluding communication that is conspicuously marked or otherwise 62 | designated in writing by the copyright owner as "Not a Contribution." 63 | 64 | "Contributor" shall mean Licensor and any individual or Legal Entity 65 | on behalf of whom a Contribution has been received by Licensor and 66 | subsequently incorporated within the Work. 67 | 68 | 2. Grant of Copyright License. Subject to the terms and conditions of 69 | this License, each Contributor hereby grants to You a perpetual, 70 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 71 | copyright license to reproduce, prepare Derivative Works of, 72 | publicly display, publicly perform, sublicense, and distribute the 73 | Work and such Derivative Works in Source or Object form. 74 | 75 | 3. Grant of Patent License. Subject to the terms and conditions of 76 | this License, each Contributor hereby grants to You a perpetual, 77 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 78 | (except as stated in this section) patent license to make, have made, 79 | use, offer to sell, sell, import, and otherwise transfer the Work, 80 | where such license applies only to those patent claims licensable 81 | by such Contributor that are necessarily infringed by their 82 | Contribution(s) alone or by combination of their Contribution(s) 83 | with the Work to which such Contribution(s) was submitted. If You 84 | institute patent litigation against any entity (including a 85 | cross-claim or counterclaim in a lawsuit) alleging that the Work 86 | or a Contribution incorporated within the Work constitutes direct 87 | or contributory patent infringement, then any patent licenses 88 | granted to You under this License for that Work shall terminate 89 | as of the date such litigation is filed. 90 | 91 | 4. Redistribution. You may reproduce and distribute copies of the 92 | Work or Derivative Works thereof in any medium, with or without 93 | modifications, and in Source or Object form, provided that You 94 | meet the following conditions: 95 | 96 | (a) You must give any other recipients of the Work or 97 | Derivative Works a copy of this License; and 98 | 99 | (b) You must cause any modified files to carry prominent notices 100 | stating that You changed the files; and 101 | 102 | (c) You must retain, in the Source form of any Derivative Works 103 | that You distribute, all copyright, patent, trademark, and 104 | attribution notices from the Source form of the Work, 105 | excluding those notices that do not pertain to any part of 106 | the Derivative Works; and 107 | 108 | (d) If the Work includes a "NOTICE" text file as part of its 109 | distribution, then any Derivative Works that You distribute must 110 | include a readable copy of the attribution notices contained 111 | within such NOTICE file, excluding those notices that do not 112 | pertain to any part of the Derivative Works, in at least one 113 | of the following places: within a NOTICE text file distributed 114 | as part of the Derivative Works; within the Source form or 115 | documentation, if provided along with the Derivative Works; or, 116 | within a display generated by the Derivative Works, if and 117 | wherever such third-party notices normally appear. The contents 118 | of the NOTICE file are for informational purposes only and 119 | do not modify the License. You may add Your own attribution 120 | notices within Derivative Works that You distribute, alongside 121 | or as an addendum to the NOTICE text from the Work, provided 122 | that such additional attribution notices cannot be construed 123 | as modifying the License. 124 | 125 | You may add Your own copyright statement to Your modifications and 126 | may provide additional or different license terms and conditions 127 | for use, reproduction, or distribution of Your modifications, or 128 | for any such Derivative Works as a whole, provided Your use, 129 | reproduction, and distribution of the Work otherwise complies with 130 | the conditions stated in this License. 131 | 132 | 5. Submission of Contributions. Unless You explicitly state otherwise, 133 | any Contribution intentionally submitted for inclusion in the Work 134 | by You to the Licensor shall be under the terms and conditions of 135 | this License, without any additional terms or conditions. 136 | Notwithstanding the above, nothing herein shall supersede or modify 137 | the terms of any separate license agreement you may have executed 138 | with Licensor regarding such Contributions. 139 | 140 | 6. Trademarks. This License does not grant permission to use the trade 141 | names, trademarks, service marks, or product names of the Licensor, 142 | except as required for reasonable and customary use in describing the 143 | origin of the Work and reproducing the content of the NOTICE file. 144 | 145 | 7. Disclaimer of Warranty. Unless required by applicable law or 146 | agreed to in writing, Licensor provides the Work (and each 147 | Contributor provides its Contributions) on an "AS IS" BASIS, 148 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 149 | implied, including, without limitation, any warranties or conditions 150 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 151 | PARTICULAR PURPOSE. You are solely responsible for determining the 152 | appropriateness of using or redistributing the Work and assume any 153 | risks associated with Your exercise of permissions under this License. 154 | 155 | 8. Limitation of Liability. In no event and under no legal theory, 156 | whether in tort (including negligence), contract, or otherwise, 157 | unless required by applicable law (such as deliberate and grossly 158 | negligent acts) or agreed to in writing, shall any Contributor be 159 | liable to You for damages, including any direct, indirect, special, 160 | incidental, or consequential damages of any character arising as a 161 | result of this License or out of the use or inability to use the 162 | Work (including but not limited to damages for loss of goodwill, 163 | work stoppage, computer failure or malfunction, or any and all 164 | other commercial damages or losses), even if such Contributor 165 | has been advised of the possibility of such damages. 166 | 167 | 9. Accepting Warranty or Additional Liability. While redistributing 168 | the Work or Derivative Works thereof, You may choose to offer, 169 | and charge a fee for, acceptance of support, warranty, indemnity, 170 | or other liability obligations and/or rights consistent with this 171 | License. However, in accepting such obligations, You may act only 172 | on Your own behalf and on Your sole responsibility, not on behalf 173 | of any other Contributor, and only if You agree to indemnify, 174 | defend, and hold each Contributor harmless for any liability 175 | incurred by, or claims asserted against, such Contributor by reason 176 | of your accepting any such warranty or additional liability. 177 | 178 | END OF TERMS AND CONDITIONS 179 | 180 | APPENDIX: How to apply the Apache License to your work. 181 | 182 | To apply the Apache License to your work, attach the following 183 | boilerplate notice, with the fields enclosed by brackets "[]" 184 | replaced with your own identifying information. (Don't include 185 | the brackets!) The text should be enclosed in the appropriate 186 | comment syntax for the file format. We also recommend that a 187 | file or class name and description of purpose be included on the 188 | same "printed page" as the copyright notice for easier 189 | identification within third-party archives. 190 | 191 | Copyright [yyyy] [name of copyright owner] 192 | 193 | Licensed under the Apache License, Version 2.0 (the "License"); 194 | you may not use this file except in compliance with the License. 195 | You may obtain a copy of the License at 196 | 197 | http://www.apache.org/licenses/LICENSE-2.0 198 | 199 | Unless required by applicable law or agreed to in writing, software 200 | distributed under the License is distributed on an "AS IS" BASIS, 201 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 202 | See the License for the specific language governing permissions and 203 | limitations under the License. -------------------------------------------------------------------------------- /tuning/bin/parseOpts: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # @Function 3 | ## parse options lib, support multiple values for one option. 4 | # 5 | # @Usage 6 | # source this script to your script file, then use func parseOpts. 7 | # parseOpts func useage sample: 8 | # $ parseOpts "a,a-long|b,b-long:|c,c-long+" -a -b bv -c c.sh -p pv -q qv arg1 \; aa bb cc 9 | # then below globle var is set: 10 | # _OPT_VALUE_a = true 11 | # _OPT_VALUE_a_long = true 12 | # _OPT_VALUE_b = bv 13 | # _OPT_VALUE_b_long = bv 14 | # _OPT_VALUE_c = (c.sh -p pv -q qv arg1) # Array type 15 | # _OPT_VALUE_c_long = (c.sh -p pv -q qv arg1) # Array type 16 | # _OPT_ARGS = (aa bb cc) # Array type 17 | # 18 | # @author Jerry Lee 19 | 20 | ##################################################################### 21 | # Utils Methods 22 | ##################################################################### 23 | 24 | _opts_colorEcho() { 25 | local color=$1 26 | shift 27 | if [ -c /dev/stdout ] ; then 28 | # if stdout is console, turn on color output. 29 | echo -ne "\033[1;${color}m" 30 | echo -n "$@" 31 | echo -e "\033[0m" 32 | else 33 | echo "$@" 34 | fi 35 | } 36 | 37 | _opts_redEcho() { 38 | _opts_colorEcho 31 "$@" 39 | } 40 | 41 | _opts_convertToVarName() { 42 | [ $# -ne 1 ] && { 43 | _opts_redEcho "NOT 1 arguemnts when call _opts_convertToVarName: $@" 44 | return 1 45 | } 46 | echo "$1" | sed 's/-/_/g' 47 | } 48 | 49 | ##################################################################### 50 | # Parse Methods 51 | # 52 | # Use Globle Variable: 53 | # * _OPT_INFO_LIST_INDEX : Option info, data structure. 54 | # _OPT_INFO_LIST_INDEX ->* _a_a_long -> option value. 55 | # * _OPT_VALUE_* : value of option. is Array type for + mode option 56 | # * _OPT_ARGS : option arguments 57 | ##################################################################### 58 | 59 | _opts_findOptMode() { 60 | [ $# -ne 1 ] && { 61 | _opts_redEcho "NOT 1 arguemnts when call _opts_findOptMode: $@" 62 | return 1 63 | } 64 | 65 | local opt="$1" # like a, a-long 66 | local idxName 67 | for idxName in "${_OPT_INFO_LIST_INDEX[@]}" ; do 68 | local idxNameArrayPlaceHolder="$idxName[@]" 69 | local -a idxNameArray=("${!idxNameArrayPlaceHolder}") 70 | 71 | local mode="${idxNameArray[0]}" 72 | 73 | local optName 74 | for optName in "${idxNameArray[@]:1:${#idxNameArray[@]}}"; do # index from 1, skip mode 75 | [ "$opt" = "${optName}" ] && { 76 | echo "$mode" 77 | return 78 | } 79 | done 80 | done 81 | 82 | echo "" 83 | } 84 | 85 | _opts_setOptBool() { 86 | [ $# -ne 2 ] && { 87 | _opts_redEcho "NOT 2 arguemnts when call _opts_setOptBool: $@" 88 | return 1 89 | } 90 | 91 | _opts_setOptValue "$@" 92 | } 93 | 94 | _opts_setOptValue() { 95 | [ $# -ne 2 ] && { 96 | _opts_redEcho "NOT 2 arguemnts when call _opts_setOptValue: $@" 97 | return 1 98 | } 99 | 100 | local opt="$1" # like a, a-long 101 | local value="$2" 102 | 103 | local idxName 104 | for idxName in "${_OPT_INFO_LIST_INDEX[@]}" ; do 105 | local idxNameArrayPlaceHolder="$idxName[@]" 106 | local -a idxNameArray=("${!idxNameArrayPlaceHolder}") 107 | 108 | local optName 109 | for optName in "${idxNameArray[@]:1:${#idxNameArray[@]}}"; do # index from 1, skip mode 110 | [ "$opt" = "$optName" ] && { 111 | local optName2 112 | for optName2 in "${idxNameArray[@]:1:${#idxNameArray[@]}}"; do 113 | local optValueVarName="_OPT_VALUE_`_opts_convertToVarName "${optName2}"`" 114 | local from='"$value"' 115 | eval "$optValueVarName=$from" # set global var! 116 | done 117 | return 118 | } 119 | done 120 | done 121 | 122 | _opts_redEcho "NOT Found option $opt!" 123 | return 1 124 | } 125 | 126 | _opts_setOptArray() { 127 | local opt="$1" # like a, a-long 128 | shift 129 | 130 | local idxName 131 | for idxName in "${_OPT_INFO_LIST_INDEX[@]}" ; do 132 | local idxNameArrayPlaceHolder="$idxName[@]" 133 | local -a idxNameArray=("${!idxNameArrayPlaceHolder}") 134 | 135 | local optName 136 | for optName in "${idxNameArray[@]:1:${#idxNameArray[@]}}"; do # index from 1, skip mode 137 | [ "$opt" = "$optName" ] && { 138 | # set _OPT_VALUE 139 | local optName2 140 | for optName2 in "${idxNameArray[@]:1:${#idxNameArray[@]}}"; do 141 | local optValueVarName="_OPT_VALUE_`_opts_convertToVarName "${optName2}"`" 142 | local from='"$@"' 143 | eval "$optValueVarName=($from)" # set global var! 144 | done 145 | return 146 | } 147 | done 148 | done 149 | 150 | _opts_redEcho "NOT Found option $opt!" 151 | return 1 152 | } 153 | 154 | _opts_cleanOptValueInfoList() { 155 | local idxName 156 | for idxName in "${_OPT_INFO_LIST_INDEX[@]}"; do 157 | local idxNameArrayPlaceHolder="$idxName[@]" 158 | local -a idxNameArray=("${!idxNameArrayPlaceHolder}") 159 | 160 | eval "unset $idxName" 161 | 162 | local optName 163 | for optName in "${idxNameArray[@]:1:${#idxNameArray[@]}}"; do # index from 1, skip mode 164 | local optValueVarName="_OPT_VALUE_`_opts_convertToVarName "$optName"`" 165 | eval "unset $optValueVarName" 166 | done 167 | done 168 | 169 | unset _OPT_INFO_LIST_INDEX 170 | unset _OPT_ARGS 171 | } 172 | 173 | parseOpts() { 174 | local optsDescription="$1" # optsDescription LIKE a,a-long|b,b-long:|c,c-long+ 175 | shift 176 | 177 | _OPT_INFO_LIST_INDEX=() # set global var! 178 | 179 | local optDescLines=`echo "$optsDescription" | 180 | # cut head and tail space 181 | sed -r 's/^\s+//;s/\s+$//' | 182 | awk -F '[\t ]*\\\\|[\t ]*' '{for(i=1; i<=NF; i++) print $i}'` 183 | 184 | local optDesc 185 | while read optDesc ; do # optDesc LIKE b,b-long: 186 | [ -z "$optDesc" ] && continue 187 | 188 | local mode="${optDesc:(-1)}" # LIKE : or + 189 | case "$mode" in 190 | +|:|-) 191 | optDesc="${optDesc:0:(${#optDesc}-1)}" # LIKE b,b-long 192 | ;; 193 | *) 194 | mode="-" 195 | ;; 196 | esac 197 | 198 | local optLines=`echo "$optDesc" | awk -F '[\t ]*,[\t ]*' '{for(i=1; i<=NF; i++) print $i}'` # LIKE "a\na-long" 199 | 200 | [ $(echo "$optLines" | wc -l) -gt 2 ] && { 201 | _opts_redEcho "Illegal option description($optDesc), more than 2 opt name!" 1>&2 202 | _opts_cleanOptValueInfoList 203 | return 220 204 | } 205 | 206 | local -a optTuple=() 207 | local opt 208 | while read opt ; do # opt LIKE a , a-long 209 | [ -z "$opt" ] && continue 210 | 211 | [ ${#opt} -eq 1 ] && { 212 | echo "$opt" | grep -E '^[a-zA-Z0-9]$' -q || { 213 | _opts_redEcho "Illegal short option name($opt in $optDesc) in option description!" 1>&2 214 | _opts_cleanOptValueInfoList 215 | return 221 216 | } 217 | } || { 218 | echo "$opt" | grep -E '^[-a-zA-Z0-9]+$' -q || { 219 | _opts_redEcho "Illegal long option name($opt in $optDesc) in option description!" 1>&2 220 | _opts_cleanOptValueInfoList 221 | return 222 222 | } 223 | } 224 | optTuple=("${optTuple[@]}" "$opt") 225 | done < <(echo "$optLines") 226 | 227 | [ ${#optTuple[@]} -gt 2 ] && { 228 | _opts_redEcho "more than 2 opt(${optTuple[@]}) in option description($optDesc)!" 1>&2 229 | _opts_cleanOptValueInfoList 230 | return 223 231 | } 232 | 233 | local idxName= 234 | local evalOpts= 235 | local o 236 | for o in "${optTuple[@]}"; do 237 | idxName="${idxName}_opts_index_name_`_opts_convertToVarName "$o"`" 238 | evalOpts="${evalOpts} $o" 239 | done 240 | 241 | eval "$idxName=($mode $evalOpts)" 242 | _OPT_INFO_LIST_INDEX=("${_OPT_INFO_LIST_INDEX[@]}" "$idxName") 243 | done < <(echo "$optDescLines") 244 | 245 | local -a args=() 246 | while true; do 247 | [ $# -eq 0 ] && break 248 | 249 | case "$1" in 250 | ---*) 251 | _opts_redEcho "Illegal option($1), more than 2 prefix '-'!" 1>&2 252 | _opts_cleanOptValueInfoList 253 | return 230 254 | ;; 255 | --) 256 | shift 257 | args=("${args[@]}" "$@") 258 | break 259 | ;; 260 | -*) # short & long option(-a, -a-long), use same read-in logic. 261 | local opt="$1" 262 | local optName=`echo "$1" | sed -r 's/^--?//'` 263 | local mode=`_opts_findOptMode "$optName"` 264 | case "$mode" in 265 | -) 266 | _opts_setOptBool "$optName" "true" 267 | shift 268 | ;; 269 | :) 270 | [ $# -lt 2 ] && { 271 | _opts_redEcho "Option $opt has NO value!" 1>&2 272 | _opts_cleanOptValueInfoList 273 | return 231 274 | } 275 | _opts_setOptValue "$optName" "$2" 276 | shift 2 277 | ;; 278 | +) 279 | shift 280 | local -a valueArray=() 281 | local foundComma="" 282 | 283 | local value 284 | for value in "$@" ; do 285 | [ ";" = "$value" ] && { 286 | foundComma=true 287 | break 288 | } || valueArray=("${valueArray[@]}" "$value") 289 | done 290 | [ "$foundComma" ] || { 291 | _opts_redEcho "value of option $opt no end comma, value = ${valueArray[@]}" 1>&2 292 | _opts_cleanOptValueInfoList 293 | return 231 294 | } 295 | shift "$((${#valueArray[@]} + 1))" 296 | _opts_setOptArray "$optName" "${valueArray[@]}" 297 | ;; 298 | *) 299 | _opts_redEcho "Undefined option $opt!" 1>&2 300 | _opts_cleanOptValueInfoList 301 | return 232 302 | ;; 303 | esac 304 | ;; 305 | *) 306 | args=("${args[@]}" "$1") 307 | shift 308 | ;; 309 | esac 310 | done 311 | _OPT_ARGS=("${args[@]}") # set global var! 312 | } 313 | 314 | ##################################################################### 315 | # Show parsed Option Info Methods 316 | ##################################################################### 317 | 318 | _opts_showOptDescInfoList() { 319 | echo "===============================================================================" 320 | echo "show option desc info list:" 321 | local idxName 322 | for idxName in "${_OPT_INFO_LIST_INDEX[@]}"; do 323 | local idxNameArrayPlaceHolder="$idxName[@]" 324 | echo "$idxName = (${!idxNameArrayPlaceHolder})" 325 | done 326 | echo "===============================================================================" 327 | } 328 | 329 | _opts_showOptValueInfoList() { 330 | echo "===============================================================================" 331 | echo "show option value info list:" 332 | local idxName 333 | for idxName in "${_OPT_INFO_LIST_INDEX[@]}"; do 334 | local idxNameArrayPlaceHolder="$idxName[@]" 335 | local -a idxNameArray=("${!idxNameArrayPlaceHolder}") 336 | 337 | local mode=${idxNameArray[0]} 338 | 339 | local optName 340 | for optName in "${idxNameArray[@]:1:${#idxNameArray[@]}}"; do # index from 1, skip mode 341 | local optValueVarName="_OPT_VALUE_`_opts_convertToVarName "$optName"`" 342 | case "$mode" in 343 | -) 344 | echo "$optValueVarName=${!optValueVarName}" 345 | ;; 346 | :) 347 | echo "$optValueVarName=${!optValueVarName}" 348 | ;; 349 | +) 350 | local optArrayValueArrayPlaceHolder="$optValueVarName[@]" 351 | echo "$optValueVarName=(${!optArrayValueArrayPlaceHolder})" 352 | ;; 353 | esac 354 | done 355 | done 356 | echo "_OPT_ARGS=(${_OPT_ARGS[@]})" 357 | echo "===============================================================================" 358 | } 359 | -------------------------------------------------------------------------------- /tuning/docs/shell.md: -------------------------------------------------------------------------------- 1 | :snail: `Shell`相关脚本 2 | ==================================== 3 | 4 | 5 | 6 | 7 | 8 | - [`Shell`使用加强](#shell%E4%BD%BF%E7%94%A8%E5%8A%A0%E5%BC%BA) 9 | - [:beer: c](#beer-c) 10 | - [示例](#%E7%A4%BA%E4%BE%8B) 11 | - [参考资料](#%E5%8F%82%E8%80%83%E8%B5%84%E6%96%99) 12 | - [:beer: colines](#beer-colines) 13 | - [示例](#%E7%A4%BA%E4%BE%8B-1) 14 | - [:beer: a2l](#beer-a2l) 15 | - [示例](#%E7%A4%BA%E4%BE%8B-2) 16 | - [:beer: ap and rp](#beer-ap-and-rp) 17 | - [示例](#%E7%A4%BA%E4%BE%8B-3) 18 | - [:beer: xpl and xpf](#beer-xpl-and-xpf) 19 | - [用法](#%E7%94%A8%E6%B3%95) 20 | - [示例](#%E7%A4%BA%E4%BE%8B-4) 21 | - [贡献者](#%E8%B4%A1%E7%8C%AE%E8%80%85) 22 | - [:beer: tcp-connection-state-counter](#beer-tcp-connection-state-counter) 23 | - [用法](#%E7%94%A8%E6%B3%95-1) 24 | - [示例](#%E7%A4%BA%E4%BE%8B-5) 25 | - [`Shell`开发/测试加强](#shell%E5%BC%80%E5%8F%91%E6%B5%8B%E8%AF%95%E5%8A%A0%E5%BC%BA) 26 | - [:beer: echo-args](#beer-echo-args) 27 | - [示例](#%E7%A4%BA%E4%BE%8B-6) 28 | - [使用方式](#%E4%BD%BF%E7%94%A8%E6%96%B9%E5%BC%8F) 29 | - [:beer: console-text-color-themes](#beer-console-text-color-themes) 30 | - [贡献者](#%E8%B4%A1%E7%8C%AE%E8%80%85-1) 31 | - [参考资料](#%E5%8F%82%E8%80%83%E8%B5%84%E6%96%99-1) 32 | - [:beer: parseOpts](#beer-parseopts) 33 | - [用法](#%E7%94%A8%E6%B3%95-2) 34 | - [示例](#%E7%A4%BA%E4%BE%8B-7) 35 | - [兼容性](#%E5%85%BC%E5%AE%B9%E6%80%A7) 36 | - [贡献者](#%E8%B4%A1%E7%8C%AE%E8%80%85-2) 37 | 38 | 39 | 40 | `Shell`使用加强 41 | ==================================== 42 | 43 | :beer: [c](../bin/c) 44 | ---------------------- 45 | 46 | 原样命令行输出,并拷贝标准输出到系统剪贴板,省去`CTRL+C`操作,优化命令行与其它应用之间的操作流。 47 | 支持`Linux`、`Mac`、`Windows`(`cygwin`、`MSSYS`)。 48 | 49 | 命令名`c`意思是`Copy`,因为这个命令我平时非常常用,所以使用一个字符的命令名,方便键入。 50 | 51 | 更多说明参见[拷贝复制命令行输出放在系统剪贴板上](http://oldratlee.com/post/2012-12-23/command-output-to-clip)。 52 | 53 | ### 示例 54 | 55 | 有3种使用风格,根据需要或是你的偏好选取。 56 | 57 | ```bash 58 | # 1. 前缀方式,后面跟上要运行的命令 59 | $ c pwd 60 | /Users/jerry 61 | $ c echo -e 'a\nb' 62 | a 63 | b 64 | # 这种使用方式,后面跟的命令不能是别名(alias),对于别名可以用下面的使用方式。 65 | 66 | # 2. 后缀方式,管道 67 | $ echo -e 'a\nb' | nl | c 68 | 1 a 69 | # gb是oh-my-zsh的别名,列出git的分支,需要后缀的方式的使用。 70 | $ gb | c 71 | 72 | # 3. 从标准输入读取内容。拷贝文件内容时这种方式最直接。 73 | $ c < id_rsa.pub 74 | ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAz+ETZEgoLeIiC0rjWewdDs0sbo8c...== a@b.com 75 | ``` 76 | 77 | ### 参考资料 78 | 79 | [拷贝复制命令行输出放在系统剪贴板上](http://oldratlee.com/post/2012-12-23/command-output-to-clip),给出了不同系统可用命令。 80 | 81 | :beer: [colines](../bin/colines) 82 | ---------------------- 83 | 84 | 彩色`cat`出文件行,方便人眼区分不同的行。 85 | 全系统支持(`Python`实现,安装`Python`即可),如`Linux`、`Mac`、`Windows`。 86 | 87 | 命令名`colines`意思是`COLorful LINES`。 88 | 89 | ### 示例 90 | 91 | ```bash 92 | $ echo a | colines 93 | a 94 | $ echo -e 'a\nb' | colines 95 | a 96 | b 97 | $ echo -e 'a\nb' | nl | colines 98 | 1 a 99 | 2 b 100 | $ colines file1 file2.txt 101 | ================================================================================ 102 | file1 103 | ================================================================================ 104 | file1 line1 105 | file1 line2 106 | ================================================================================ 107 | file2.txt 108 | ================================================================================ 109 | file2 line1 110 | file2 line2 111 | ``` 112 | 113 | 注:上面显示中,没有彩色,在控制台上运行可以看出彩色效果。 114 | 115 | :beer: [a2l](../bin/a2l) 116 | ---------------------- 117 | 118 | 按行彩色输出参数,方便人眼查看。 119 | 支持`Linux`、`Mac`、`Windows`(`cygwin`、`MSSYS`)。 120 | 121 | 命令名`a2l`意思是`Arguments to(2) Lines`。 122 | 123 | ### 示例 124 | 125 | ```bash 126 | $ a2l *.java 127 | A.java 128 | B.java 129 | ... 130 | 131 | # zsh支持 **/* 跨目录glob,可以方便搜索,但是输出内容是空格分隔的不方便查看。 132 | # 把参数按行输出方便查看 或是 grep 133 | $ a2l **/*.sh 134 | swtrunk.sh 135 | tcp-connection-state-counter.sh 136 | test-cases/parseOpts-test.sh 137 | test-cases/self-installer.sh 138 | ... 139 | ``` 140 | 141 | 注:上面显示中,没有彩色,在控制台上运行可以看出彩色效果。 142 | 143 | :beer: [ap](../bin/ap) and [rp](../bin/rp) 144 | ---------------------- 145 | 146 | 批量转换文件路径为绝对路径/相对路径,会自动跟踪链接并规范化路径。 147 | 支持`Linux`、`Mac`、`Windows`(`cygwin`、`MSSYS`)。 148 | 149 | 命令名`ap`意思是`Absolute Path`,`rp`是`Relative Path`。 150 | 151 | ### 示例 152 | 153 | ```bash 154 | # ap缺省打印当前路径的绝对路径 155 | $ ap 156 | /home/admin/useful-scripts/test 157 | $ ap .. 158 | /home/admin/useful-scripts 159 | # 支持多个参数 160 | $ ap .. ../.. /etc /etc/../etc 161 | /home/admin/useful-scripts 162 | /home/admin 163 | /etc 164 | /etc 165 | 166 | # rp当一个参数时,打印相对于当前路径的相对路径 167 | $ rp /home 168 | ../.. 169 | # 多于一个参数时,打印相对于最后一个参数的相对路径 170 | $ rp /home /etc/../etc /home/admin 171 | .. 172 | ../../etc 173 | ``` 174 | 175 | :beer: [xpl](../bin/xpl) and [xpf](../bin/xpf) 176 | ---------------------- 177 | 178 | 在命令行中快速完成 在文件浏览器中 打开/选中 指定的文件或文件夹的操作。 179 | 持`Linux`、`Mac`、`Windows`(`cygwin`、`MSSYS`)。 180 | 181 | * `xpl`:在文件浏览器中打开指定的文件或文件夹。 182 | \# `xpl`是`explorer`的缩写。 183 | * `xpf`: 在文件浏览器中打开指定的文件或文件夹,并选中。 184 | \# `xpf`是`explorer and select file`的缩写。 185 | 186 | ### 用法 187 | 188 | ```bash 189 | xpl 190 | # 缺省打开当前目录 191 | xpl <文件或是目录>... 192 | # 打开多个文件或目录 193 | 194 | xpf 195 | # 缺省打开当前目录 196 | xpf <文件或是目录>... 197 | # 打开多个文件或目录 198 | ``` 199 | 200 | ### 示例 201 | 202 | ```bash 203 | xpl /path/to/dir 204 | xpl /path/to/foo.txt 205 | xpl /path/to/dir1 /path/to/foo1.txt 206 | xpf /path/to/foo1.txt 207 | xpf /path/to/dir1 /path/to/foo1.txt 208 | ``` 209 | 210 | ### 贡献者 211 | 212 | [Linhua Tan](https://github.com/toolchainX)修复Linux的选定Bug。 213 | 214 | :beer: [tcp-connection-state-counter](../bin/tcp-connection-state-counter) 215 | ---------------------- 216 | 217 | 统计各个`TCP`连接状态的个数。 218 | 支持`Linux`、`Mac`、`Windows`(`cygwin`、`MSSYS`)。 219 | 220 | 像`Nginx`、`Apache`的机器上需要查看,`TCP`连接的个数,以判定 221 | 222 | - 连接数、负荷 223 | - 是否有攻击,查看`SYN_RECV`数(`SYN`攻击) 224 | - `TIME_WAIT`数,太多会导致`TCP: time wait bucket table overflow`。 225 | 226 | ### 用法 227 | 228 | ```bash 229 | tcp-connection-state-counter.sh 230 | ``` 231 | 232 | ### 示例 233 | 234 | ```bash 235 | $ tcp-connection-state-counter.sh 236 | ESTABLISHED 290 237 | TIME_WAIT 212 238 | SYN_SENT 17 239 | ``` 240 | 241 | ### 贡献者 242 | 243 | [sunuslee](https://github.com/sunuslee)改进此脚本,增加对`MacOS`的支持。 [#56](https://github.com/oldratlee/useful-scripts/pull/56) 244 | 245 | `Shell`开发/测试加强 246 | ==================================== 247 | 248 | :beer: [echo-args](../bin/echo-args) 249 | ---------------------- 250 | 251 | 在编写脚本时,常常要确认输入参数是否是期望的:参数个数,参数值(可能包含有人眼不容易发现的空格问题)。 252 | 支持`Linux`、`Mac`、`Windows`(`cygwin`、`MSSYS`)。 253 | 254 | 这个脚本输出脚本收到的参数。在控制台运行时,把参数值括起的括号显示成 **红色**,方便人眼查看。 255 | 256 | ### 示例 257 | 258 | ```bash 259 | $ ./echo-args.sh 1 " 2 foo " "3 3" 260 | 0/3: [./echo-args.sh] 261 | 1/3: [1] 262 | 2/3: [ 2 foo ] 263 | 3/3: [3 3] 264 | ``` 265 | 266 | ### 使用方式 267 | 268 | 需要查看某个脚本(实际上也可以是其它的可执行程序)输出参数时,可以这么做: 269 | 270 | * 把要查看脚本重命名。 271 | * 建一个`echo-args.sh`脚本的符号链接到要查看参数的脚本的位置,名字和查看脚本一样。 272 | 273 | 这样可以不改其它的程序,查看到输入参数的信息。 274 | 275 | :beer: [console-text-color-themes](../bin/console-text-color-themes) 276 | ---------------------- 277 | 278 | 显示`Terminator`的全部文字彩色组合的效果及其打印方式。 279 | 支持`Linux`、`Mac`、`Windows`(`cygwin`、`MSSYS`)。 280 | 281 | 脚本中,也给出了`colorEcho`和`colorEchoWithoutNewLine`函数更方便输出彩色文本,用法: 282 | 283 | ```bash 284 | colorEcho <颜色样式> <要输出的文本>... 285 | colorEchoWithoutNewLine <颜色样式> <要输出的文本>... 286 | ``` 287 | 288 | ```bash 289 | # 输出红色文本 290 | colorEcho "0;31;40" "Hello world!" 291 | # 输出黄色带下划线的文本 292 | colorEchoWithoutNewLine "4;33;40" "Hello world!" "Hello Hell!" 293 | ``` 294 | 295 | `console-text-color-themes.sh`的运行效果图如下: 296 | ![console-text-color-themes.sh的运行效果图](console-colorful-text.png) 297 | 298 | ### 贡献者 299 | 300 | [姜太公](https://github.com/jzwlqx)提供循环输出彩色组合的脚本。 301 | 302 | ### 参考资料 303 | 304 | - [utensil](https://github.com/utensil)的[在Bash下输出彩色的文本](http://utensil.github.io/tech/2007/09/10/colorful-bash.html),这是篇很有信息量很钻研的文章! 305 | 306 | :beer: [parseOpts](../bin/parseOpts.sh) 307 | ---------------------- 308 | 309 | 命令行选项解析库,加强支持选项有多个值(即数组)。 310 | 支持`Linux`、`Mac`、`Windows`(`cygwin`、`MSSYS`)。 311 | \# 自己写一个命令行选项解析函数,是因为[`bash`](http://linux.die.net/man/1/bash)的`buildin`命令[`getopts`](http://linux.die.net/man/1/getopts)和加强版本命令[`getopt`](http://linux.die.net/man/1/getopt)都不支持数组的值。 312 | 313 | 指定选项的多个值(即数组)的风格模仿[`find`](http://linux.die.net/man/1/find)命令的`-exec`选项: 314 | 315 | ```bash 316 | $ find . -name \*.txt -exec echo "find file: " {} \; 317 | find file: foo.txt 318 | find file: bar.txt 319 | ... 320 | ``` 321 | 322 | ### 用法 323 | 324 | `parseOpts`函数的第一个参数是要解析的选项说明,后面跟实际要解析的输入参数。 325 | 326 | 选项说明可以长选项和短选项,用逗号分隔,如`a,a-long`。不同选项的说明间用竖号分隔,如`a,a-long|b,b-long:`。 327 | 328 | 选项说明最后可以有选项类型说明: 329 | 330 | - `-`: 无参数的选项。即有选项则把值设置成`true`。这是 ***缺省*** 的类型。 331 | - `:`: 有参数的选项,值只有一个。 332 | - `+`: 有多个参数值的选项。值列表要以`;`表示结束。 333 | 注意,`;`是`Bash`的元字符(用于一行中多个命令分隔),所以加上转义写成`\;`(当然也可以按你的喜好写成`";"`或`';'`)。 334 | 335 | 实际要解析的输入参数往往是你的脚本参数,这样`parseOpts`函数调用一般是: 336 | 337 | ```bash 338 | parseOpts "a,a-long|b,b-long:|c,c-long+" "$@" 339 | # "$@" 即是回放你的脚本参数 340 | ``` 341 | 342 | 通过约定的全局变量来获取选项和参数: 343 | 344 | * 选项名为`a`,通过全局变量`_OPT_VALUE_a`来获取选项的值。 345 | * 选项名为`a-long`,通过全局变量`_OPT_VALUE_a_long`来获取选项的值。 346 | 即,把选项名的`-`转`_`,再加上前缀`_OPT_VALUE_`对应的全局变量来获得选项值。 347 | * 除了选项剩下的参数,通过全局变量`_OPT_ARGS`来获取。 348 | 349 | 按照惯例,输入参数中如果有`--`表示之后参数中不再有选项,即之后都是参数。 350 | 351 | ### 示例 352 | 353 | ```bash 354 | # 导入parseOpts 355 | source /path/to/parseOpts 356 | 357 | parseOpts "a,a-long|b,b-long:|c,c-long+" -a -b bv --c-long c.sh -p pv -q qv arg1 \; aa bb cc 358 | # 可以通过下面全局变量来获得解析的参数值: 359 | # _OPT_VALUE_a = true 360 | # _OPT_VALUE_a_long = true 361 | # _OPT_VALUE_b = bv 362 | # _OPT_VALUE_b_long = bv 363 | # _OPT_VALUE_c = (c.sh -p pv -q qv arg1) ,数组类型 364 | # _OPT_VALUE_c_long = (c.sh -p pv -q qv arg1) ,数组类型 365 | # _OPT_ARGS = (aa bb cc) ,数组类型 366 | ``` 367 | 368 | `--`的使用效果示例: 369 | 370 | ```bash 371 | # 导入parseOpts 372 | source /path/to/parseOpts 373 | 374 | parseOpts "a,a-long|b,b-long:|c,c-long+" -a -b bv -- --c-long c.sh -p pv -q qv arg1 \; aa bb cc 375 | # 可以通过下面全局变量来获得解析的参数值: 376 | # _OPT_VALUE_a = true 377 | # _OPT_VALUE_a_long = true 378 | # _OPT_VALUE_b = bv 379 | # _OPT_VALUE_b_long = bv 380 | # _OPT_VALUE_c 没有设置过 381 | # _OPT_VALUE_c_long 没有设置过 382 | # _OPT_ARGS = (--c-long c.sh -p pv -q qv arg1 ';' aa bb cc) ,数组类型 383 | ``` 384 | 385 | ### 兼容性 386 | 387 | 这个脚本比较复杂,测试过的环境有: 388 | 389 | 1. `bash --version` 390 | `GNU bash, version 4.1.5(1)-release (x86_64-pc-linux-gnu)` 391 | `uname -a` 392 | `Linux foo-host 2.6.32-41-generic #94-Ubuntu SMP Fri Jul 6 18:00:34 UTC 2012 x86_64 GNU/Linux` 393 | 1. `bash --version` 394 | `GNU bash, version 3.2.53(1)-release (x86_64-apple-darwin14)` 395 | `uname -a` 396 | `Darwin foo-host 14.0.0 Darwin Kernel Version 14.0.0: Fri Sep 19 00:26:44 PDT 2014; root:xnu-2782.1.97~2/RELEASE_X86_64 x86_64 i386 MacBookPro10,1 Darwin` 397 | 1. `bash --version` 398 | `GNU bash, version 3.00.15(1)-release (i386-redhat-linux-gnu)` 399 | `uname -a` 400 | `Linux foo-host 2.6.9-103.ELxenU #1 SMP Wed Mar 14 16:31:15 CST 2012 i686 i686 i386 GNU/Linux` 401 | 402 | ### 贡献者 403 | 404 | [Khotyn Huang](https://github.com/khotyn)指出`bash` `3.0`下使用有问题,并提供`bash` `3.0`的测试机器。 405 | 406 | :beer: [xpl](../bin/xpl) and [xpf](../bin/xpf) 407 | ---------------------- 408 | 409 | * `xpl`:在文件浏览器中打开指定的文件或文件夹。 410 | \# `xpl`是`explorer`的缩写。 411 | * `xpf`: 在文件浏览器中打开指定的文件或文件夹,并选中。 412 | \# `xpf`是`explorer and select file`的缩写。 413 | 414 | ### 用法 415 | 416 | ```bash 417 | xpl 418 | # 缺省打开当前目录 419 | xpl <文件或是目录>... 420 | # 打开多个文件或目录 421 | 422 | xpf 423 | # 缺省打开当前目录 424 | xpf <文件或是目录>... 425 | # 打开多个文件或目录 426 | ``` 427 | 428 | ### 示例 429 | 430 | ```bash 431 | xpl /path/to/dir 432 | xpl /path/to/foo.txt 433 | xpl /path/to/dir1 /path/to/foo1.txt 434 | xpf /path/to/foo1.txt 435 | xpf /path/to/dir1 /path/to/foo1.txt 436 | ``` 437 | 438 | ### 贡献者 439 | 440 | [Linhua Tan](https://github.com/toolchainX)修复Linux的选定Bug。 441 | 442 | :beer: [show-cpu-and-memory](../bin/show-cpu-and-memory) 443 | ---------------------- 444 | 445 | 显示当前cpu和内存使用状况,包括全局和各个进程的。 446 | 447 | ### 用法 448 | 449 | 直接执行即可 450 | 451 | :beer: [monitor-host](../bin/monitor-host) 452 | ---------------------- 453 | 454 | 监控当前的内存、cpu、io以及网络状况,写入相应的log文件。 455 | 456 | ### 用法 457 | 458 | ``` 459 | Usage: monitor-host [OPTION] [delay [count]] 460 | 461 | Example: monitor-host -l ./monitor_logs 462 | 463 | Options: 464 | -l, --log-path monitor logs output path,default is ./monitor_logs 465 | -h, --help display this help and exit 466 | --stop stop monitor processes 467 | delay is the delay between updates in seconds. default is 1 468 | count is the number of log outputs. deault is 10 469 | ``` 470 | 471 | 建议使用crontab,定时调用此脚本 472 | 473 | :beer: [tpl/run-cmd-tpl.sh](../tpl/run-cmd-tpl.sh) 474 | ---------------------- 475 | 476 | linux下后台执行守护程序的模板shell脚本。 477 | 478 | ### 用法 479 | 480 | 修改文件中此部分的值为需要执行的程序即可 481 | 482 |
483 | MONITOR_APPNAME="SwitchMonitor"
484 | COMMAND="$JAVA_COMMAND $OPTS $MONITOR_JAR"
485 | STOP_COMMAND="kill -9"
486 | NAME="OM Switch Monitor"
487 | 
488 | 489 | :beer: [check-vm](../bin/check-vm.py) 490 | ---------------------- 491 | 492 | 检查当前linux是否是在虚拟机上,包括openvz/xen、pv/uml、VmWare。 493 | 494 | ### 用法 495 | 496 | 直接执行即可 497 | 498 | :beer: [get-pip](../bin/get-pip.py) 499 | ---------------------- 500 | 501 | 安装pip 502 | 503 | ### 用法 504 | 505 | 直接执行即可 -------------------------------------------------------------------------------- /tuning/docs/java.md: -------------------------------------------------------------------------------- 1 | :snail: `Java`相关脚本 2 | ==================================== 3 | 4 | 5 | 6 | 7 | 8 | - [:beer: show-busy-java-threads](#beer-show-busy-java-threads) 9 | - [用法](#%E7%94%A8%E6%B3%95) 10 | - [示例](#%E7%A4%BA%E4%BE%8B) 11 | - [贡献者](#%E8%B4%A1%E7%8C%AE%E8%80%85) 12 | - [:beer: show-duplicate-java-classes](#beer-show-duplicate-java-classes) 13 | - [用法](#%E7%94%A8%E6%B3%95-1) 14 | - [`JDK`开发场景使用说明](#jdk%E5%BC%80%E5%8F%91%E5%9C%BA%E6%99%AF%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E) 15 | - [对于一般的工程](#%E5%AF%B9%E4%BA%8E%E4%B8%80%E8%88%AC%E7%9A%84%E5%B7%A5%E7%A8%8B) 16 | - [对于`Web`工程](#%E5%AF%B9%E4%BA%8Eweb%E5%B7%A5%E7%A8%8B) 17 | - [`Android`开发场景使用说明](#android%E5%BC%80%E5%8F%91%E5%9C%BA%E6%99%AF%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E) 18 | - [示例](#%E7%A4%BA%E4%BE%8B-1) 19 | - [贡献者](#%E8%B4%A1%E7%8C%AE%E8%80%85-1) 20 | - [:beer: find-in-jars](#beer-find-in-jars) 21 | - [用法](#%E7%94%A8%E6%B3%95-2) 22 | - [示例](#%E7%A4%BA%E4%BE%8B-2) 23 | - [参考资料](#%E5%8F%82%E8%80%83%E8%B5%84%E6%96%99) 24 | 25 | 26 | 27 | :beer: [show-busy-java-threads](../java/bin/show-busy-java-threads) 28 | ---------------------- 29 | 30 | 用于快速排查`Java`的`CPU`性能问题(`top us`值过高),自动查出运行的`Java`进程中消耗`CPU`多的线程,并打印出其线程栈,从而确定导致性能问题的方法调用。 31 | 目前只支持`Linux`。原因是`Mac`、`Windows`的`ps`命令不支持列出线程,更多信息参见[#33](https://github.com/oldratlee/useful-scripts/issues/33),欢迎提供解法。 32 | 33 | PS,如何操作可以参见[@bluedavy](http://weibo.com/bluedavy)的《分布式Java应用》的【5.1.1 cpu消耗分析】一节,说得很详细: 34 | 35 | 1. `top`命令找出有问题`Java`进程及线程`id`: 36 | 1. 开启线程显示模式 37 | 1. 按`CPU`使用率排序 38 | 1. 记下`Java`进程`id`及其`CPU`高的线程`id` 39 | 1. 用进程`id`作为参数,`jstack`有问题的`Java`进程 40 | 1. 手动转换线程`id`成十六进制(可以用`printf %x 1234`) 41 | 1. 查找十六进制的线程`id`(可以用`grep`) 42 | 1. 查看对应的线程栈 43 | 44 | 查问题时,会要多次这样操作以确定问题,上面过程**太繁琐太慢了**。 45 | 46 | ### 用法 47 | 48 | ```bash 49 | show-busy-java-threads [Options] [delay [ucount]] 50 | # 从 所有的 Java进程中找出最消耗CPU的线程(缺省5个),打印出其线程栈。 51 | 52 | show-busy-java-threads -c <要显示的线程栈数> 53 | 54 | show-busy-java-threads -c <要显示的线程栈数> -p <指定的Java Process> 55 | 56 | # -F选项:执行jstack命令时加上-F选项(强制jstack),一般情况不需要使用 57 | show-busy-java-threads -p <指定的Java Process> -F 58 | 59 | show-busy-java-threads -s <指定jstack命令的全路径> 60 | # 对于sudo方式的运行,JAVA_HOME环境变量不能传递给root, 61 | # 而root用户往往没有配置JAVA_HOME且不方便配置, 62 | # 显式指定jstack命令的路径就反而显得更方便了 63 | 64 | show-busy-java-threads -a <输出记录到的文件> 65 | 66 | show-busy-java-threads -c <要显示的线程栈数> -p <指定的Java Process> <刷新间隔秒数> <刷新次数> 67 | 68 | ############################## 69 | # 注意: 70 | ############################## 71 | # 如果Java进程的用户 与 执行脚本的当前用户 不同,则jstack不了这个Java进程。 72 | # 为了能切换到Java进程的用户,需要加sudo来执行,即可以解决: 73 | sudo show-busy-java-threads 74 | 75 | # 帮助信息 76 | $ show-busy-java-threads -h 77 | Usage: show-busy-java-threads [OPTION] [delay [ucount]] 78 | Find out the highest cpu consumed threads of java, and print the stack of these threads. 79 | Example: show-busy-java-threads -c 10 80 | 81 | Options: 82 | -p, --pid find out the highest cpu consumed threads from the specifed java process, 83 | default from all java process. 84 | -c, --count set the thread count to show, default is 5 85 | -a, --append-file specify the file to append output as log 86 | -s, --jstack-path specify the path of jstack command 87 | -F, --force set jstack to force a thread dump(use jstack -F option) 88 | -S, --jstack-file-dir specifies the directory for storing jstack output files, and keep files. 89 | default store jstack output files at tmp dir, and auto remove after run. 90 | use this option to keep files so as to review jstack later. 91 | -m, --mix-native-frames set jstack to print both java and native frames (mixed mode). 92 | -l, --lock-info set jstack with long listing. Prints additional information about locks. 93 | -d, --top-delay specifies the delay between top samples, default is 0.5 (second). 94 | get thread cpu percentage during this delay interval. 95 | more info see top -d option. eg: -d 1 (1 second). 96 | -P, --use-ps use ps command to find busy thread(cpu usage) instead of top command, 97 | default use top command, because cpu usage of ps command is expressed as 98 | the percentage of time spent running during the entire lifetime of a process, 99 | this is not ideal. 100 | -h, --help display this help and exit 101 | delay is the delay between updates in seconds. when this is not set, it will output once. 102 | ucount is the number of updates. when delay is set, ucount is not set, it will output in unstop mode. 103 | ``` 104 | 105 | ### 示例 106 | 107 | ```bash 108 | $ show-busy-java-threads 109 | [1] Busy(57.0%) thread(23355/0x5b3b) stack of java process(23269) under user(admin): 110 | "pool-1-thread-1" prio=10 tid=0x000000005b5c5000 nid=0x5b3b runnable [0x000000004062c000] 111 | java.lang.Thread.State: RUNNABLE 112 | at java.text.DateFormat.format(DateFormat.java:316) 113 | at com.xxx.foo.services.common.DateFormatUtil.format(DateFormatUtil.java:41) 114 | at com.xxx.fooared.monitor.schedule.AppMonitorDataAvgScheduler.run(AppMonitorDataAvgScheduler.java:127) 115 | at com.xxx.foo.services.common.utils.AliTimer$2.run(AliTimer.java:128) 116 | at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) 117 | at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) 118 | at java.lang.Thread.run(Thread.java:662) 119 | 120 | [2] Busy(26.1%) thread(24018/0x5dd2) stack of java process(23269) under user(admin): 121 | "pool-1-thread-2" prio=10 tid=0x000000005a968800 nid=0x5dd2 runnable [0x00000000420e9000] 122 | java.lang.Thread.State: RUNNABLE 123 | at java.util.Arrays.copyOf(Arrays.java:2882) 124 | at java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:100) 125 | at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:572) 126 | at java.lang.StringBuffer.append(StringBuffer.java:320) 127 | - locked <0x00000007908d0030> (a java.lang.StringBuffer) 128 | at java.text.SimpleDateFormat.format(SimpleDateFormat.java:890) 129 | at java.text.SimpleDateFormat.format(SimpleDateFormat.java:869) 130 | at java.text.DateFormat.format(DateFormat.java:316) 131 | at com.xxx.foo.services.common.DateFormatUtil.format(DateFormatUtil.java:41) 132 | at com.xxx.fooared.monitor.schedule.AppMonitorDataAvgScheduler.run(AppMonitorDataAvgScheduler.java:126) 133 | at com.xxx.foo.services.common.utils.AliTimer$2.run(AliTimer.java:128) 134 | at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) 135 | at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) 136 | ... 137 | ``` 138 | 139 | 上面的线程栈可以看出,`CPU`消耗最高的2个线程都在执行`java.text.DateFormat.format`,业务代码对应的方法是`shared.monitor.schedule.AppMonitorDataAvgScheduler.run`。可以基本确定: 140 | 141 | - `AppMonitorDataAvgScheduler.run`调用`DateFormat.format`次数比较频繁。 142 | - `DateFormat.format`比较慢。(这个可以由`DateFormat.format`的实现确定。) 143 | 144 | 多个执行几次`show-busy-java-threads`,如果上面情况高概率出现,则可以确定上面的判定。 145 | \# 因为调用越少代码执行越快,则出现在线程栈的概率就越低。 146 | 147 | 分析`shared.monitor.schedule.AppMonitorDataAvgScheduler.run`实现逻辑和调用方式,以优化实现解决问题。 148 | 149 | ### 贡献者 150 | 151 | - [silentforce](https://github.com/silentforce)改进此脚本,增加对环境变量`JAVA_HOME`的判断。 [#15](https://github.com/oldratlee/useful-scripts/pull/15) 152 | - [liuyangc3](https://github.com/liuyangc3) 153 | - 发现并解决`jstack`非当前用户`Java`进程的问题。 [#50](https://github.com/oldratlee/useful-scripts/pull/50) 154 | - 优化性能,通过`read -a`简化反复的`awk`操作。 [#51](https://github.com/oldratlee/useful-scripts/pull/51) 155 | 156 | :beer: [show-duplicate-java-classes](../java/bin/show-duplicate-java-classes) 157 | ---------------------- 158 | 159 | 找出`Java Lib`(`Java`库,即`Jar`文件)或`Class`目录(类目录)中的重复类。 160 | 全系统支持(`Python`实现,安装`Python`即可),如`Linux`、`Mac`、`Windows`。 161 | 162 | `Java`开发的一个麻烦的问题是`Jar`冲突(即多个版本的`Jar`),或者说重复类。会出`NoSuchMethod`等的问题,还不见得当时出问题。找出有重复类的`Jar`,可以防患未然。 163 | 164 | ### 用法 165 | 166 | - 通过脚本参数指定`Libs`目录,查找目录下`Jar`文件,收集`Jar`文件中`Class`文件以分析重复类。可以指定多个`Libs`目录。 167 | 注意,只会查找这个目录下`Jar`文件,不会查找子目录下`Jar`文件。因为`Libs`目录一般不会用子目录再放`Jar`,这样也避免把去查找不期望`Jar`。 168 | - 通过`-c`选项指定`Class`目录,直接收集这个目录下的`Class`文件以分析重复类。可以指定多个`Class`目录。 169 | 170 | ```bash 171 | # 查找当前目录下所有Jar中的重复类 172 | show-duplicate-java-classes 173 | 174 | # 查找多个指定目录下所有Jar中的重复类 175 | show-duplicate-java-classes path/to/lib_dir1 /path/to/lib_dir2 176 | 177 | # 查找多个指定Class目录下的重复类。 Class目录 通过 -c 选项指定 178 | show-duplicate-java-classes -c path/to/class_dir1 -c /path/to/class_dir2 179 | 180 | # 查找指定Class目录和指定目录下所有Jar中的重复类的Jar 181 | show-duplicate-java-classes path/to/lib_dir1 /path/to/lib_dir2 -c path/to/class_dir1 -c path/to/class_dir2 182 | ``` 183 | 184 | #### `JDK`开发场景使用说明 185 | 186 | 以`Maven`作为构建工程示意过程。 187 | 188 | ##### 对于一般的工程 189 | 190 | ```sh 191 | # 在项目模块目录下执行,拷贝依赖Jar到目录target/dependency下 192 | $ mvn dependency:copy-dependencies -DincludeScope=runtime 193 | ... 194 | # 检查重复类 195 | $ show-duplicate-java-classes target/dependency 196 | ... 197 | ``` 198 | 199 | ##### 对于`Web`工程 200 | 201 | 对于`Web`工程,即`war` `maven`模块,会打包生成`war`文件。 202 | 203 | ```sh 204 | # 在war模块目录下执行,生成war文件 205 | $ mvn install 206 | ... 207 | # 解压war文件,war文件中包含了应用的依赖的Jar文件 208 | $ unzip target/*.war -d target/war 209 | ... 210 | # 检查重复类 211 | $ show-duplicate-java-classes -c target/war/WEB-INF/classes target/war/WEB-INF/lib 212 | ... 213 | ``` 214 | 215 | #### `Android`开发场景使用说明 216 | 217 | `Android`开发,有重复类在编译打包时会报`[Dex Loader] Unable to execute dex: Multiple dex files define Lorg/foo/xxx/Yyy`。 218 | 219 | 但只会给出一个重复类名,如果重复类比较多时,上面打包/报错/排查会要进行多次,而`Android`的打包比较费时,这个过程比较麻烦,希望可以一次把所有重复类都列出来,一起排查掉。 220 | 221 | 以`Gradle`作为构建工程示意过程。 222 | 223 | 在`App`的`build.gradle`中添加拷贝库到目录`build/dependencies`下。 224 | 225 | ```java 226 | task copyDependencies(type: Copy) { 227 | def dest = new File(buildDir, "dependencies") 228 | 229 | // clean dir 230 | dest.deleteDir() 231 | dest.mkdirs() 232 | 233 | // fill dir with dependencies 234 | from configurations.compile into dest 235 | } 236 | ``` 237 | 238 | ```sh 239 | # 拷贝依赖 240 | $ ./gradlew app:copyDependencies 241 | ... 242 | # 检查重复类 243 | $ show-duplicate-java-classes app/build/dependencies 244 | ... 245 | ``` 246 | 247 | ### 示例 248 | 249 | ```bash 250 | $ show-duplicate-java-classes WEB-INF/lib 251 | COOL! No duplicate classes found! 252 | 253 | ================================================================================ 254 | class paths to find: 255 | ================================================================================ 256 | 1 : WEB-INF/lib/sourceforge.spring.modules.context-2.5.6.SEC02.jar 257 | 2 : WEB-INF/lib/misc.htmlparser-0.0.0.jar 258 | 3 : WEB-INF/lib/normandy.client-1.0.2.jar 259 | ... 260 | 261 | $ show-duplicate-java-classes -c WEB-INF/classes WEB-INF/lib 262 | Found duplicate classes in below class path: 263 | 1 (293@2): WEB-INF/lib/sourceforge.spring-2.5.6.SEC02.jar WEB-INF/lib/sourceforge.spring.modules.orm-2.5.6.SEC02.jar 264 | 2 (2@3): WEB-INF/lib/servlet-api-3.0-alpha-1.jar WEB-INF/lib/jsp-api-2.1-rev-1.jar WEB-INF/lib/jstl-api-1.2-rev-1.jar 265 | 3 (104@2): WEB-INF/lib/commons-io-2.2.jar WEB-INF/lib/jakarta.commons.io-2.0.jar 266 | 4 (6@3): WEB-INF/lib/jakarta.commons.logging-1.1.jar WEB-INF/lib/commons-logging-1.1.1.jar WEB-INF/lib/org.slf4j.jcl104-over-slf4j-1.5.6.jar 267 | 5 (344@2): WEB-INF/lib/sourceforge.spring-2.5.6.SEC02.jar WEB-INF/lib/sourceforge.spring.modules.context-2.5.6.SEC02.jar 268 | ... 269 | 270 | ================================================================================ 271 | Duplicate classes detail info: 272 | ================================================================================ 273 | 1 (293@2): WEB-INF/lib/sourceforge.spring-2.5.6.SEC02.jar WEB-INF/lib/sourceforge.spring.modules.orm-2.5.6.SEC02.jar 274 | 1 org/springframework/orm/toplink/TopLinkTemplate$13.class 275 | 2 org/springframework/orm/hibernate3/HibernateTemplate$24.class 276 | 3 org/springframework/orm/jpa/vendor/HibernateJpaDialect.class 277 | 4 org/springframework/orm/hibernate3/TypeDefinitionBean.class 278 | 5 org/springframework/orm/hibernate3/SessionHolder.class 279 | ... 280 | 2 (2@3): WEB-INF/lib/servlet-api-3.0-alpha-1.jar WEB-INF/lib/jsp-api-2.1-rev-1.jar WEB-INF/lib/jstl-api-1.2-rev-1.jar 281 | 1 javax/servlet/ServletException.class 282 | 2 javax/servlet/ServletContext.class 283 | 3 (104@2): WEB-INF/lib/commons-io-2.2.jar WEB-INF/lib/jakarta.commons.io-2.0.jar 284 | 1 org/apache/commons/io/input/ProxyReader.class 285 | 2 org/apache/commons/io/output/FileWriterWithEncoding.class 286 | 3 org/apache/commons/io/output/TaggedOutputStream.class 287 | 4 org/apache/commons/io/filefilter/NotFileFilter.class 288 | 5 org/apache/commons/io/filefilter/TrueFileFilter.class 289 | ... 290 | ... 291 | 292 | ================================================================================ 293 | class paths to find: 294 | ================================================================================ 295 | 1 : WEB-INF/lib/sourceforge.spring.modules.context-2.5.6.SEC02.jar 296 | 2 : WEB-INF/lib/misc.htmlparser-0.0.0.jar 297 | 3 : WEB-INF/lib/normandy.client-1.0.2.jar 298 | 4 : WEB-INF/lib/xml.xmlgraphics__batik-css-1.7.jar-1.7.jar 299 | 5 : WEB-INF/lib/jakarta.ecs-1.4.2.jar 300 | ... 301 | ``` 302 | 303 | ### 贡献者 304 | 305 | [tgic](https://github.com/tg123)提供此脚本。友情贡献者的链接[commandlinefu.cn](http://commandlinefu.cn/)|[微博linux命令行精选](http://weibo.com/u/2674868673) 306 | 307 | :beer: [find-in-jars](../java/bin/find-in-jars) 308 | ---------------------- 309 | 310 | 在当前目录下所有`jar`文件里,查找类或资源文件。 311 | 支持`Linux`、`Mac`、`Windows`(`cygwin`、`MSSYS`) 312 | 313 | ### 用法 314 | 315 | ```bash 316 | # 在当前目录下所有`jar`文件里,查找类或资源文件。 317 | find-in-jars 'log4j\.properties' 318 | find-in-jars 'log4j\.xml$' 319 | find-in-jars log4j\\.xml$ # 和上面命令一样,Shell转义的不同写法而已 320 | find-in-jars 'log4j(\.properties|\.xml)$' 321 | 322 | # -d选项 指定 查找目录(覆盖缺省的当前目录) 323 | find-in-jars 'log4j\.properties$' -d /path/to/find/directory 324 | # 支持多个查找目录 325 | find-in-jars 'log4j\.properties' -d /path/to/find/directory1 -d /path/to/find/directory2 326 | 327 | # 帮助信息 328 | $ find-in-jars -h 329 | Usage: find-in-jars [OPTION]... PATTERN 330 | Find file in the jar files under specified directory(recursive, include subdirectory). 331 | The pattern default is *extended* regex. 332 | 333 | Example: 334 | find-in-jars.sh 'log4j\.properties' 335 | find-in-jars.sh '^log4j(\.properties|\.xml)$' # search file log4j.properties/log4j.xml at zip root 336 | find-in-jars.sh 'log4j\.properties$' -d /path/to/find/directory 337 | find-in-jars.sh 'log4j\.properties' -d /path/to/find/dir1 -d /path/to/find/dir2 338 | 339 | Options: 340 | -d, --dir the directory that find jar files, default is current directory. 341 | this option can specify multiply times to find in multiply directory. 342 | -E, --extended-regexp PATTERN is an extended regular expression (*default*) 343 | -F, --fixed-strings PATTERN is a set of newline-separated strings 344 | -G, --basic-regexp PATTERN is a basic regular expression 345 | -P, --perl-regexp PATTERN is a Perl regular expression 346 | -h, --help display this help and exit 347 | ``` 348 | 349 | 注意,Pattern缺省是`grep`的 **扩展**正则表达式。 350 | 351 | ### 示例 352 | 353 | ```bash 354 | # 在当前目录下的所有Jar文件中,查找出 log4j.properties文件 355 | $ find-in-jars 'log4j\.properties$' 356 | ./hadoop-core-0.20.2-cdh3u3.jar!log4j.properties 357 | 358 | # 查找出 以Service结尾的类 359 | $ ./find-in-jars 'Service.class$' 360 | ./WEB-INF/libs/spring-2.5.6.SEC03.jar!org/springframework/stereotype/Service.class 361 | ./rpc-benchmark-0.0.1-SNAPSHOT.jar!com/taobao/rpc/benchmark/service/HelloService.class 362 | ...... 363 | 364 | # 在指定的多个目录的Jar文件中,查找出 properties文件 365 | $ find-in-jars '\.properties$' -d ../WEB-INF/lib -d ../deploy/lib | grep -v '/pom\.properties$' 366 | ../WEB-INF/lib/aspectjtools-1.6.2.jar!org/aspectj/ajdt/ajc/messages.properties 367 | ../WEB-INF/lib/aspectjtools-1.6.2.jar!org/aspectj/ajdt/internal/compiler/parser/readableNames.properties 368 | ../WEB-INF/lib/aspectjweaver-1.8.8.jar!org/aspectj/weaver/XlintDefault.properties 369 | ../WEB-INF/lib/aspectjweaver-1.8.8.jar!org/aspectj/weaver/weaver-messages.properties 370 | ../deploy/lib/groovy-all-1.1-rc-1.jar!groovy/ui/InteractiveShell.properties 371 | ../deploy/lib/groovy-all-1.1-rc-1.jar!org/codehaus/groovy/tools/shell/CommandAlias.properties 372 | ../deploy/lib/httpcore-4.3.3.jar!org/apache/http/version.properties 373 | ../deploy/lib/httpmime-4.2.2.jar!org/apache/http/entity/mime/version.properties 374 | ../deploy/lib/javax.servlet-api-3.0.1.jar!javax/servlet/LocalStrings_fr.properties 375 | ../deploy/lib/javax.servlet-api-3.0.1.jar!javax/servlet/http/LocalStrings_es.properties 376 | ...... 377 | ``` 378 | 379 | ### 参考资料 380 | 381 | [在多个Jar(Zip)文件查找Log4J配置文件的Shell命令行](http://oldratlee.com/458/tech/shell/find-file-in-jar-zip-files.html) 382 | -------------------------------------------------------------------------------- /tuning/java/bin/show-busy-java-threads: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # @Function 3 | ## Find out the highest cpu consumed threads of java, and print the stack of these threads. 4 | # 5 | # @Usage 6 | # $ ./show-busy-java-threads 7 | # 8 | # @online-doc https://github.com/oldratlee/useful-scripts/blob/master/docs/java.md#beer-show-busy-java-threads 9 | # @author Jerry Lee (oldratlee at gmail dot com) 10 | # @author superhj1987 (superhj1987 at 126 dot com) 11 | 12 | readonly PROG="`basename $0`" 13 | readonly -a COMMAND_LINE=("$0" "$@") 14 | # Get current user name via whoami command 15 | # See https://www.lifewire.com/current-linux-user-whoami-command-3867579 16 | # Because if run command by `sudo -u`, env var $USER is not rewritten/correct, just inherited from outside! 17 | readonly USER="`whoami`" 18 | 19 | ################################################################################ 20 | # util functions 21 | ################################################################################ 22 | 23 | # NOTE: $'foo' is the escape sequence syntax of bash 24 | readonly ec=$'\033' # escape char 25 | readonly eend=$'\033[0m' # escape end 26 | 27 | colorEcho() { 28 | local color=$1 29 | shift 30 | 31 | # if stdout is console, turn on color output. 32 | [ -t 1 ] && echo "$ec[1;${color}m$@$eend" || echo "$@" 33 | } 34 | 35 | colorPrint() { 36 | local color=$1 37 | shift 38 | 39 | colorEcho "$color" "$@" 40 | # use "{} &> /dev/null" to discard bash error message: 41 | # line 42: xxx.log: Permission denied 42 | { [ -n "$append_file" ] && echo "$@" >> "$append_file"; } &> /dev/null 43 | } 44 | 45 | redPrint() { 46 | colorPrint 31 "$@" 47 | } 48 | 49 | greenPrint() { 50 | colorPrint 32 "$@" 51 | } 52 | 53 | yellowPrint() { 54 | colorPrint 33 "$@" 55 | } 56 | 57 | bluePrint() { 58 | colorPrint 36 "$@" 59 | } 60 | 61 | normalPrint() { 62 | echo "$@" 63 | [ -n "$append_file" ] && echo "$@" >> "$append_file" 64 | } 65 | 66 | fatal() { 67 | redPrint "$@" 1>&2 68 | exit 1 69 | } 70 | 71 | usage() { 72 | local -r exit_code="$1" 73 | shift 74 | [ -n "$exit_code" -a "$exit_code" != 0 ] && local -r out=/dev/stderr || local -r out=/dev/stdout 75 | 76 | (( $# > 0 )) && { echo "$@"; echo; } > $out 77 | 78 | > $out cat < specify the file to append output as log 92 | -s, --jstack-path specify the path of jstack command 93 | -F, --force set jstack to force a thread dump(use jstack -F option) 94 | -S, --jstack-file-dir specifies the directory for storing jstack output files, and keep files. 95 | default store jstack output files at tmp dir, and auto remove after run. 96 | use this option to keep files so as to review jstack later. 97 | -m, --mix-native-frames set jstack to print both java and native frames (mixed mode). 98 | -l, --lock-info set jstack with long listing. Prints additional information about locks. 99 | -d, --top-delay specifies the delay between top samples, default is 0.5 (second). 100 | get thread cpu percentage during this delay interval. 101 | more info see top -d option. eg: -d 1 (1 second). 102 | -P, --use-ps use ps command to find busy thread(cpu usage) instead of top command, 103 | default use top command, because cpu usage of ps command is expressed as 104 | the percentage of time spent running during the entire lifetime of a process, 105 | this is not ideal. 106 | -h, --help display this help and exit 107 | delay is the delay between updates in seconds. when this is not set, it will output once. 108 | ucount is the number of updates. when delay is set, ucount is not set, it will output in unstop mode. 109 | EOF 110 | 111 | exit $exit_code 112 | } 113 | 114 | ################################################################################ 115 | # Check os support 116 | ################################################################################ 117 | 118 | uname | grep '^Linux' -q || fatal "Error: $PROG only support Linux, not support `uname` yet!" 119 | 120 | ################################################################################ 121 | # parse options 122 | ################################################################################ 123 | 124 | # NOTE: ARGS can not be declared as readonly!! 125 | # readonly declaration make exit code of assignment to be always 0, aka. the exit code of `getopt` in subshell is discarded. 126 | # tested on bash 4.2.46 127 | 128 | ARGS=`getopt -n "$PROG" -a -o p:c:a:s:S:Pd:Fmlh -l pid:,count:,append-file:,jstack-path:,jstack-file-dir:,use-ps,top-delay:,force,mix-native-frames,lock-info,help -- "$@"` 129 | [ $? -ne 0 ] && { echo; usage 1; } 130 | eval set -- "${ARGS}" 131 | 132 | while true; do 133 | case "$1" in 134 | -c|--count) 135 | count="$2" 136 | shift 2 137 | ;; 138 | -p|--pid) 139 | pid="$2" 140 | shift 2 141 | ;; 142 | -a|--append-file) 143 | append_file="$2" 144 | shift 2 145 | ;; 146 | -s|--jstack-path) 147 | jstack_path="$2" 148 | shift 2 149 | ;; 150 | -S|--jstack-file-dir) 151 | jstack_file_dir="$2" 152 | shift 2 153 | ;; 154 | -P|--use-ps) 155 | use_ps=true 156 | shift 157 | ;; 158 | -d|--top-delay) 159 | top_delay="$2" 160 | shift 2 161 | ;; 162 | -F|--force) 163 | force=-F 164 | shift 165 | ;; 166 | -m|--mix-native-frames) 167 | mix_native_frames=-m 168 | shift 169 | ;; 170 | -l|--lock-info) 171 | more_lock_info=-l 172 | shift 173 | ;; 174 | -h|--help) 175 | usage 176 | ;; 177 | --) 178 | shift 179 | break 180 | ;; 181 | esac 182 | done 183 | count=${count:-5} 184 | use_ps=${use_ps:-false} 185 | top_delay=${top_delay:-0.5} 186 | update_delay=${1:-0} 187 | update_limit=${2:-0} 188 | 189 | # check the directory of append-file(-a) mode, create if not exsit. 190 | if [ -n "$append_file" ]; then 191 | if [ -e "$append_file" ]; then 192 | [ ! -f "$append_file" ] && fatal "Error: $append_file(specified by option -a, for storing run output files) exists but is not a file!" 193 | [ ! -w "$append_file" ] && fatal "Error: file $append_file(specified by option -a, for storing run output files) exists but is not writable!" 194 | else 195 | append_file_dir="$(dirname "$append_file")" 196 | if [ -e "$append_file_dir" ]; then 197 | [ ! -d "$append_file_dir" ] && fatal "Error: directory $append_file_dir(specified by option -a, for storing run output files) exists but is not a directory!" 198 | [ ! -w "$append_file_dir" ] && fatal "Error: directory $append_file_dir(specified by option -a, for storing run output files) exists but is not writable!" 199 | else 200 | mkdir -p "$append_file_dir" && fatal "Error: fail to create directory $append_file_dir(specified by option -a, for storing run output files)!" 201 | fi 202 | fi 203 | fi 204 | 205 | # check jstack-file directory(-S) mode, create directory if not exsit. 206 | if [ -n "$jstack_file_dir" ]; then 207 | if [ -e "$jstack_file_dir" ]; then 208 | [ ! -d "$jstack_file_dir" ] && fatal "Error: $jstack_file_dir(specified by option -S, for storing jstack output files) exists but is not a directory!" 209 | [ ! -w "$jstack_file_dir" ] && fatal "Error: directory $jstack_file_dir(specified by option -S, for storing jstack output files) exists but is not writable!" 210 | else 211 | mkdir -p "$jstack_file_dir" && fatal "Error: fail to create directory $jstack_file_dir(specified by option -S, for storing jstack output files)!" 212 | fi 213 | fi 214 | 215 | ################################################################################ 216 | # check the existence of jstack command 217 | ################################################################################ 218 | 219 | if [ -n "$jstack_path" ]; then 220 | [ -f "$jstack_path" ] || fatal "Error: $jstack_path is NOT found!" 221 | [ -x "$jstack_path" ] || fatal "Error: $jstack_path is NOT executalbe!" 222 | elif which jstack &> /dev/null; then 223 | jstack_path="`which jstack`" 224 | else 225 | [ -z "$JAVA_HOME" ] && fatal "Error: jstack not found on PATH and No JAVA_HOME setting! Use -s option set jstack path manually." 226 | [ -f "$JAVA_HOME/bin/jstack" ] || fatal "Error: jstack not found on PATH and \$JAVA_HOME/bin/jstack($JAVA_HOME/bin/jstack) file does NOT exists! Use -s option set jstack path manually." 227 | [ -x "$JAVA_HOME/bin/jstack" ] || fatal "Error: jstack not found on PATH and \$JAVA_HOME/bin/jstack($JAVA_HOME/bin/jstack) is NOT executalbe! Use -s option set jstack path manually." 228 | jstack_path="$JAVA_HOME/bin/jstack" 229 | fi 230 | 231 | ################################################################################ 232 | # biz logic 233 | ################################################################################ 234 | 235 | readonly run_timestamp="`date "+%Y-%m-%d_%H:%M:%S.%N"`" 236 | readonly uuid="${PROG}_${run_timestamp}_${RANDOM}_$$" 237 | readonly tmp_store_dir="/tmp/${uuid}" 238 | mkdir -p "$tmp_store_dir" 239 | 240 | if [ -n "$jstack_file_dir" ]; then 241 | readonly jstack_file_path_prefix="$jstack_file_dir/jstack_${run_timestamp}_" 242 | else 243 | readonly jstack_file_path_prefix="$tmp_store_dir/jstack_${run_timestamp}_" 244 | fi 245 | 246 | cleanupWhenExit() { 247 | rm /tmp/${uuid}_* &> /dev/null 248 | } 249 | trap "cleanupWhenExit" EXIT 250 | 251 | headInfo() { 252 | colorEcho "0;34;42" ================================================================================ 253 | echo "$(date "+%Y-%m-%d %H:%M:%S.%N") [$(( update_count + 1 ))/$update_limit]: ${COMMAND_LINE[@]}" 254 | colorEcho "0;34;42" ================================================================================ 255 | echo 256 | } 257 | 258 | # output field: pid, thread id(lwp), pcpu, user 259 | # order by pcpu(percentage of cpu usage),this value reprents the cpu running time for this process / total process time,no realtime cpu usage. 260 | findBusyJavaThreadsByPs() { 261 | if [ -n "${pid}" ]; then 262 | local -r ps_options="-p $pid" 263 | else 264 | local -r ps_options="-C java" 265 | fi 266 | # 1. sort by %cpu by ps option `--sort -pcpu` 267 | # 2. use wide output(unlimited width) by ps option `-ww` 268 | # avoid trunk user column to username_fo+ or $uid alike 269 | ps $ps_options -wwLo pid,lwp,pcpu,user --sort -pcpu --no-headers | head -n "${count}" 270 | } 271 | 272 | # top with output field: thread id, %cpu, thsi value is realtime cpu usage 273 | __top_threadId_cpu() { 274 | # 1. sort by %cpu by top option `-o %CPU` 275 | # unfortunately, top version 3.2 does not support -o option(supports from top version 3.3+), 276 | # use 277 | # HOME="$tmp_store_dir" top -H -b -n 1 278 | # combined 279 | # sort 280 | # instead of 281 | # HOME="$tmp_store_dir" top -H -b -n 1 -o '%CPU' 282 | # 2. change HOME env var when run top, 283 | # so as to prevent top command output format being change by .toprc user config file unexpectedly 284 | # 3. use option `-d 0.5`(interval 0.5 second) and `-n 2`(show 2 times), and use second time update data 285 | # to get cpu percentage of thread in 0.5 second interval 286 | HOME="$tmp_store_dir" top -H -b -d $top_delay -n 2 | 287 | awk '{ 288 | if (idx == 4 && $NF == "java") # $NF is command 289 | # only print 4th text block(idx == 3), aka. process info of second top update 290 | print $1 " " $9 # $1 is thread id, $9 is %cpu 291 | if ($0 == "") 292 | idx++ 293 | }' | sort -k2,2nr 294 | } 295 | 296 | # output format is same as function findBusyJavaThreadsByPs 297 | findBusyJavaThreadsByTop() { 298 | if [ -n "${pid}" ]; then 299 | local -r ps_options="-p $pid" 300 | else 301 | local -r ps_options="-C java" 302 | fi 303 | # ps output field: pid, thread id(lwp), user 304 | local -r ps_out="$(ps $ps_options -wwLo pid,lwp,user --no-headers)" 305 | 306 | local idx=0 307 | local -a line 308 | while IFS=" " read -a line ; do 309 | (( idx < count )) || break 310 | 311 | local threadId="${line[0]}" 312 | local pcpu="${line[1]}" 313 | 314 | # output field: pid, threadId, pcpu, user 315 | local output_fields="$( echo "$ps_out" | 316 | awk -v "threadId=$threadId" -v "pcpu=$pcpu" '$2==threadId { 317 | print $1 " " threadId " " pcpu " " $3; exit 318 | }' )" 319 | if [ -n "$output_fields" ]; then 320 | (( idx++ )) 321 | echo "$output_fields" 322 | fi 323 | done < <( __top_threadId_cpu ) 324 | } 325 | 326 | printStackOfThreads() { 327 | local update_round_num="$1" 328 | 329 | local -a line 330 | local idx=0 331 | while IFS=" " read -a line ; do 332 | local pid="${line[0]}" 333 | local threadId="${line[1]}" 334 | local threadId0x="0x`printf %x ${threadId}`" 335 | local pcpu="${line[2]}" 336 | local user="${line[3]}" 337 | 338 | (( idx++ )) 339 | local jstackFile="$jstack_file_path_prefix${update_round_num}_${pid}" 340 | [ -f "${jstackFile}" ] || { 341 | if [ "${user}" == "${USER}" ]; then 342 | # run without sudo, when java process user is current user 343 | "$jstack_path" ${force} $mix_native_frames $more_lock_info ${pid} > ${jstackFile} 344 | elif [ $UID == 0 ]; then 345 | # if java process user is not current user, must run jstack with sudo 346 | sudo -u "${user}" "$jstack_path" ${force} $mix_native_frames $more_lock_info ${pid} > ${jstackFile} 347 | else 348 | # current user is not root user, so can not run with sudo; print error message and rerun suggestion 349 | redPrint "[$idx] Fail to jstack busy(${pcpu}%) thread(${threadId}/${threadId0x}) stack of java process(${pid}) under user(${user})." 350 | redPrint "User of java process($user) is not current user($USER), need sudo to rerun:" 351 | yellowPrint " sudo ${COMMAND_LINE[@]}" 352 | normalPrint 353 | continue 354 | fi || { 355 | redPrint "[$idx] Fail to jstack busy(${pcpu}%) thread(${threadId}/${threadId0x}) stack of java process(${pid}) under user(${user})." 356 | normalPrint 357 | rm "${jstackFile}" &> /dev/null 358 | continue 359 | } 360 | } 361 | 362 | bluePrint "[$idx] Busy(${pcpu}%) thread(${threadId}/${threadId0x}) stack of java process(${pid}) under user(${user}):" 363 | 364 | if [ -n "$mix_native_frames" ]; then 365 | local sed_script="/--------------- $threadId ---------------/,/^---------------/ { 366 | /--------------- $threadId ---------------/b # skip first seperator line 367 | /^---------------/s/.*// # replace sencond seperator line to empty line 368 | p 369 | }" 370 | elif [ -n "$force" ]; then 371 | local sed_script="/^Thread ${threadId}:/,/^$/p" 372 | else 373 | local sed_script="/nid=${threadId0x} /,/^$/p" 374 | fi 375 | sed "$sed_script" -n ${jstackFile} | tee ${append_file:+-a "$append_file"} 376 | done 377 | } 378 | 379 | update_count=0 380 | while true 381 | do 382 | [ -n "$append_file" ] && head_info >> "$append_file" 383 | headInfo 384 | 385 | if $use_ps; then 386 | findBusyJavaThreadsByPs 387 | else 388 | findBusyJavaThreadsByTop 389 | fi | printStackOfThreads $(( update_count + 1 )) 390 | 391 | if (( "$update_delay" <= 0 )); then #不需要定时刷新数据 392 | break 393 | fi 394 | 395 | ((update_count++)) 396 | if (( "$update_limit" > 0 && "$update_count" == "$update_limit" )); then #刷新次数到达上限 397 | break # 398 | fi 399 | 400 | sleep "$update_delay" #休眠 401 | done 402 | 403 | # if update_limit <= 0, infinite loop till user interupted (eg: CTRL+C) 404 | #for ((i = 0; update_limit <= 0 || i < update_limit; ++i)); do 405 | # [ "$i" -gt 0 ] && sleep "$update_delay" 406 | 407 | # [ -n "$append_file" ] && headInfo >> "$append_file" 408 | # [ "$update_count" -ne 1 ] && headInfo 409 | 410 | # ps -Leo pid,lwp,user,comm,pcpu --no-headers | { 411 | # [ -z "${pid}" ] && 412 | # awk '$4=="java"{print $0}' || 413 | # awk -v "pid=${pid}" '$1==pid,$4=="java"{print $0}' 414 | # } | sort -k5 -r -n | head -n "${count}" | printStackOfThreads 415 | #done 416 | --------------------------------------------------------------------------------