Skip to content

user20161119/useful-shells

 
 

Repository files navigation

useful-shells

把平时有用的手动操作做成脚本,这样可以便捷的使用。

有好的脚本 或是 平时常用但没有写成脚本的操作,欢迎提供和分享!

下载使用

直接clone工程

简单方便,不过要安装有git

git clone git://github.com/oldratlee/useful-shells.git
# 使用Release分支的内容
git checkout release

# 更新
git pull

下载单个文件

show-busy-java-threads.sh为例:

wget --no-check-certificate https://raw.github.com/oldratlee/useful-shells/release/show-busy-java-threads.sh
chmod +x show-busy-java-threads.sh

打包下载

下载文件release.zip

wget --no-check-certificate https://github.com/oldratlee/useful-shells/archive/release.zip

show-busy-java-threads.sh

在排查JavaCPU性能问题时(top us值过高),要找出Java进程中消耗CPU多的线程,并查看它的线程栈,从而找出导致性能问题的方法调用。

PS:如何操作可以参见@bluedavy的《分布式Java应用》的【5.1.1 cpu消耗分析】一节,说得很详细:top命令开启线程显示模式、按CPU使用率排序、记下Java进程里CPU高的线程号;手动转成十六进制(可以用printf %x 1234);jstack,grep十六进制的线程id,找到线程栈。查问题时,会要多次这样操作,太繁琐。

这个脚本的功能是,打印出在运行的Java进程中,消耗CPU最多的线程栈(缺省是5个线程)。

用法

show-busy-java-threads.sh -c <要显示的线程栈数>
# 上面会从所有的Java进程中找出最消耗CPU的线程,这样用更方便。

show-busy-java-threads.sh -c <要显示的线程栈数> -p <指定的Java Process>

示例

$ show-busy-java-threads.sh 
The stack of busy(57.0%) thread(23355/0x5b3b) of java process(23269) of user(admin):
"pool-1-thread-1" prio=10 tid=0x000000005b5c5000 nid=0x5b3b runnable [0x000000004062c000]
   java.lang.Thread.State: RUNNABLE
	at java.text.DateFormat.format(DateFormat.java:316)
	at com.xxx.foo.services.common.DateFormatUtil.format(DateFormatUtil.java:41)
	at com.xxx.foo.shared.monitor.schedule.AppMonitorDataAvgScheduler.run(AppMonitorDataAvgScheduler.java:127)
	at com.xxx.foo.services.common.utils.AliTimer$2.run(AliTimer.java:128)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
	at java.lang.Thread.run(Thread.java:662)

The stack of busy(26.1%) thread(24018/0x5dd2) of java process(23269) of user(admin):
"pool-1-thread-2" prio=10 tid=0x000000005a968800 nid=0x5dd2 runnable [0x00000000420e9000]
   java.lang.Thread.State: RUNNABLE
	at java.util.Arrays.copyOf(Arrays.java:2882)
	at java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:100)
	at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:572)
	at java.lang.StringBuffer.append(StringBuffer.java:320)
	- locked <0x00000007908d0030> (a java.lang.StringBuffer)
	at java.text.SimpleDateFormat.format(SimpleDateFormat.java:890)
	at java.text.SimpleDateFormat.format(SimpleDateFormat.java:869)
	at java.text.DateFormat.format(DateFormat.java:316)
	at com.xxx.foo.services.common.DateFormatUtil.format(DateFormatUtil.java:41)
	at com.xxx.foo.shared.monitor.schedule.AppMonitorDataAvgScheduler.run(AppMonitorDataAvgScheduler.java:126)
	at com.xxx.foo.services.common.utils.AliTimer$2.run(AliTimer.java:128)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
...

贡献者

silentforce改进此脚本,增加对环境变量JAVA_HOME的判断。

parseOpts.sh

提供命令行选项解析函数parseOpts,支持选项的值有多个值(即数组)。
# 自己写一个命令行选项解析函数,是因为bash的buildin命令getopts和加强版本命令getopt都不支持数组的值。

用法

parseOpts函数的第一个参数是要解析的选项说明,后面跟实际要解析的输入参数。

选项说明可以长选项和短选项,用逗号分隔,如a,a-long。不同选项的说明间用坚号分隔,如a,a-long|b,b-long:

选项说明最后可以有选项类型说明:

  • -,无参数的选项。即有选项则把值设置成true。这是缺省的类型。
  • :,有参数的选项,值只有一个。
  • +,有多个参数值的选项。值要以;表示结束。注意,;Bash的元字符,可以写成\;,具体参见用法示例。

实际要解析的输入参数往往是你的脚本参数,这样parseOpts函数调用一般是:

parseOpts "a,a-long|b,b-long:|c,c-long+" "$@"
# "$@" 即是回放你的脚本参数

通过约定的全局变量来获取选项值:

  • 选项名为a,通过全局变量_OPT_VALUE_a来获取选项的值。
  • 选项名为a-long,通过全局变量_OPT_VALUE_a_long来获取选项的值。

即,把选项名的-_,再加上前缀_OPT_VALUE_对应的全局变量来获得选项值。

选项及选项值剩下的参数,通过_OPT_ARGS来获取。

示例

# 导入parseOpts.sh
source /path/to/parseOpts.sh

parseOpts "a,a-long|b,b-long:|c,c-long+" -a -b bv -c c.sh -p pv -q qv arg1 \; aa bb cc
# 可以通过下面全局变量来获得解析的参数值:
#	_OPT_VALUE_a = true
#	_OPT_VALUE_a_long = true
#	_OPT_VALUE_b = bv
#	_OPT_VALUE_b_long = bv
#	_OPT_VALUE_c = (c.sh -p pv -q qv arg1) ,数组类型
#	_OPT_VALUE_c_long = (c.sh -p pv -q qv arg1) ,数组类型
#	_OPT_ARGS = (aa bb cc) ,数组类型

cp-svn-url.sh

拷贝当前svn目录对应的远程分支。

用法

cp-svn-url.sh # 缺省使用当前目录作为SVN工作目录
cp-svn-url.sh /path/to/svn/work/directory

示例

$ cp-svn-url.sh
http://www.foo.com/project1/branches/feature1 copied!

贡献者

ivanzhangwb提供此脚本。

参考资料

拷贝复制命令行输出放在系统剪贴板上,给出了不同系统可用命令。

find-in-jars.sh

在当前目录下所有Jar文件里,查找文件名。

用法

find-in-jars.sh 'log4j\.properties'
find-in-jars.sh 'log4j\.xml$' -d /path/to/find/directory
find-in-jars.sh log4j\\.xml
find-in-jars.sh 'log4j\.properties|log4j\.xml'

注意,后面Pattern是grep的扩展正则表达式。

示例

$ ./find-in-jars 'Service.class$'
./WEB-INF/libs/spring-2.5.6.SEC03.jar!org/springframework/stereotype/Service.class
./rpc-benchmark-0.0.1-SNAPSHOT.jar!com/taobao/rpc/benchmark/service/HelloService.class

参考资料

在多个Jar(Zip)文件查找Log4J配置文件的Shell命令行

echo-args.sh

在编写脚本时,常常要确认输入参数是否是期望的:参数个数,参数值(可能包含有人眼不容易发现的空格问题)。

这个脚本输出脚本收到的参数。在控制台运行时,把参数值括起的括号显示成 红色,方便人眼查看。

示例

$ ./echo-args.sh 1 "  2 foo  " "3        3"
0/3: [./echo-args.sh]
1/3: [1]
2/3: [  2 foo  ]
3/3: [3        3]

使用方式

需要查看某个脚本(实际上也可以是其它的可执行程序)输出参数时,可以这么做:

  • 把要查看脚本重命名。
  • 建一个echo-args.sh脚本的符号链接到要查看参数的脚本的位置,名字和查看脚本一样。

这样可以不改其它的程序,查看到输入参数的信息。

xpl and xpf

  • xpl:在文件浏览器中打开指定的文件或文件夹。
    # xpl是explorer的缩写。
  • xpf: 在文件浏览器中打开指定的文件或文件夹,并选中。
    # xpf是explorer and select file的缩写。

用法&示例

xpl /path/to/dir
xpl /path/to/foo.txt
xpl /path/to/dir1 /path/to/foo1.txt
xpf /path/to/foo1.txt
xpf /path/to/dir1 /path/to/foo1.txt

process-command.sh

如果一个分布式应用部署在多个节点上,分别登陆到每一台机器上维护非常麻烦,process-command.sh能够帮助你在一台机器上启动节点进程。

示例

  • ./process-command.sh ustc ustc2013 "ls -la"
  • ./process-command.sh ustc ustc2013 "./inm-bigdata-worker-1.0.0-SNAPSHOT/bin/server.sh start"
  • ./process-command.sh ustc ustc2013 "./inm-bigdata-worker-1.0.0-SNAPSHOT/bin/server.sh stop &"