File: README.md
🐌 useful scripts for making developer's everyday life easier and happier, involved java, shell etc.
👉 平时有用的手动操作做成脚本,以便捷地使用,让开发的日常生活更轻松些。 💕
欢迎 👏 💖
- 提问,提交 Issue
- 分享平时自己常用但没有写成脚本的功能(即需求、想法),提交Issue
- 优化改进,Fork 后提通过 Pull Request 贡献代码
- 提供的自己好用脚本实现,Fork 后提通过 Pull Request 提供
本仓库的脚本(如Java相关脚本)在阿里等公司(如随身云,见awesome-scripts仓库说明)的线上生产环境部署使用。
如果你的公司有部署使用,欢迎使用通过 Issue:who's using | 用户反馈收集 告知,方便互相交流反馈~ 💗
🔰 快速下载&使用
source <(curl -fsSL https://raw.githubusercontent.com/oldratlee/useful-scripts/release-3.x/test/self-installer.sh)更多下载&使用方式,参见下载使用。
📚 使用文档
☕ [`Java`相关脚本](docs/java.md)
- show-busy-java-threads
用于快速排查Java的CPU性能问题(top us值过高),自动查出运行的Java进程中消耗CPU多的线程,并打印出其线程栈,从而确定导致性能问题的方法调用。 - show-duplicate-java-classes
找出jar文件和class目录中的重复类。用于排查Java类冲突问题。 - find-in-jars
在目录下所有jar文件里,查找类或资源文件。
🐚 [`Shell`相关脚本](docs/shell.md)
Shell使用加强:
- c
原样命令行输出,并拷贝标准输出到系统剪贴板,省去CTRL+C操作,优化命令行与其它应用之间的操作流。 - coat and taoc
彩色cat/tac出文件行,方便人眼区分不同的行。 - a2l
按行彩色输出参数,方便人眼查看。 - uq
不重排序输入完成整个输入行的去重。相比系统的uniq命令加强的是可以跨行去重,不需要排序输入。 - ap and rp
批量转换文件路径为绝对路径/相对路径,会自动跟踪链接并规范化路径。 - cp-into-docker-run
一个Docker使用的便利脚本。拷贝本机的执行文件到指定的docker container中并在docker container中执行。 - tcp-connection-state-counter
统计各个TCP连接状态的个数。用于方便排查系统连接负荷问题。 - xpl and xpf
在命令行中快速完成 在文件浏览器中 打开/选中 指定的文件或文件夹的操作,优化命令行与其它应用之间的操作流。
Shell开发/测试加强:
- echo-args
输出脚本收到的参数,在控制台运行时,把参数值括起的括号显示成 红色,方便人眼查看。用于调试脚本参数输入。 - console-text-color-themes.sh
显示Terminator的全部文字彩色组合的效果及其打印方式,用于开发Shell的彩色输出。 - parseOpts.sh
命令行选项解析库,加强支持选项有多个值(即数组)。
🎓 Developer Guide
为用户提供有用的功能,当然是这个库的首要的价值体现和存在理由。
但作为一个开源项目,每个人都可以看到源码实现,这个库或许能做得更多。
🎯 面向开发者的目标
- 将
Shell/Bash作为线上生产环境使用的专业编程语言。 - 期望体现
Shell/Bash脚本 生产环境级的严谨开发方式与最佳实践,进而有可能示例与改善在生产环境中Shell脚本的质量状况。
PS:
- 虽然上面是自己期望的目标,但自己在
Shell语言上一定会有很多理解和使用上的问题、在这些实现脚本中也会很多需要的改进,可以一起学习、讨论与实践~ 💕 - 这个库中脚本的实现也有使用
Python。
关于`Shell`脚本
命令行(CLI)几乎是每个程序员每天都在使用的工具。相比图形界面工具(GUI),命令行有着自己不可替代的便利性和优越性。
命令行里写出来其实就是Shell脚本,可以说每个开发者会写Shell脚本(或多或少)。在生产环境的功能实现中,也常会看到Shell脚本(虽然不如主流语言那么常见)。
可能正因为上面所说的Shell脚本的便利性和大众性:
Shell脚本有不少是顺手实现的(包括生产环境用的Shell脚本);Shell脚本的实现常常可能质量不高,会引发线上严重的故障。
🚦 开发约定
在这个库中的Shell脚本:
- 统一使用
Bash 3.2+; - 面向生产环境,尽可能使用严谨安全的开发方式。
Shell用Bash的原因是:
- 目前仍然是主流的
Shell,并且在不同环境基本上都缺省部署了。 - 在
Google的Shell风格指南中,明确说到了:Bash是唯一被允许执行的shell脚本语言。 - 统一用
Bash,可以避免不同Shell之间差异所带来的风险与没有收益的复杂性。- 有大量的
Shell实现,sh、bash、zsh、fish、csh、tcsh、ksh、ash、dash…… - 不同的
Shell有各种差异,深坑勿入。
- 有大量的
- 个人系统学习过的是
Bash,比较理解熟悉。
PS: 虽然交互Shell个人已经使用Zsh + oh-my-zsh,但在严谨的Shell脚本开发时还是使用Bash。
📚 `Shell`学习与开发的资料
更多资料参见 子文档。
- 🛠️ 开发规范与工具
Google Shell Style Guide| 中文版koalaman/shellcheck:ShellCheck, a static analysis tool for shell scriptsmvdan/sh(shfmt):shfmtformats shell programs
- 👷
Bash/Shell最佳实践与安全编程文章- Use the Unofficial Bash Strict Mode (Unless You Looove Debugging)
- Bash Pitfalls: 编程易犯的错误 - 团子的小窝:Part 1 | Part 2 | Part 3 | Part 4 | 英文原文:Bash Pitfalls
- 不要自己去指定
sh的方式去执行脚本
- 🎶 Tips
- 让你提升命令行效率的 Bash 快捷键 【完整版】
补充:ctrl + x, ctrl + e就地打开文本编辑器来编辑当前命令行,对于复杂命令行特别有用 - 应该知道的Linux技巧 | 酷 壳 - CoolShell
- 简洁的 Bash Programming 技巧 - 团子的小窝:Part 1 | Part 2 | Part 3
- 让你提升命令行效率的 Bash 快捷键 【完整版】
- 💎 系统学习 — 看文章、了解Tips完全不能替代系统学习才能真正理解并专业开发!
- 《Bash Pocket Reference》
力荐!说明简单直接结构体系的佳作,专业Bash编程必备!且16年的第二版更新到了新版的Bash 4 - 《学习bash》 上面那本的展开版
- 官方资料
bash man| 中文版- Bash Reference Manual - gnu.org | 中文版
Bash参考手册,讲得全面且有深度,比如会全面地讲解不同转义的区别、命令的解析过程,这有助统一深入的方式认识Bash整个执行方式和过程。这些内容在其它书中往往不会讲(因为复杂难于深入浅出的讲解),但却一通百通的关键。
- Advanced Bash-Scripting Guide: An in-depth exploration of the art of shell scripting.
- 命令行的艺术 -
jlevy/the-art-of-command-line awesome-lists/awesome-bash: A curated list of delightful Bash scripts and resources.alebcay/awesome-shell: A curated list of awesome command-line frameworks, toolkits, guides and gizmos.- 更多书籍参见个人整理的书籍豆列
Bash/Shell
- 《Bash Pocket Reference》
File: docs/developer-guide.md
📚 `Shell`学习与开发的资料
- 🛠️ 开发规范与工具
Google Shell Style Guide| 中文版koalaman/shellcheck:ShellCheck, a static analysis tool for shell scriptsmvdan/sh(shfmt):shfmtformats shell programs
- 👷
Bash/Shell最佳实践与安全编程文章- Use the Unofficial Bash Strict Mode (Unless You Looove Debugging)
- Bash Pitfalls: 编程易犯的错误 - 团子的小窝:Part 1 | Part 2 | Part 3 | Part 4 | 英文原文:Bash Pitfalls
- 编写可靠shell脚本的八个建议 - xshell.net
- Shell 编码风格 - 团子的小窝
- Bash 优良编程实践
- 不要自己去指定
sh的方式去执行脚本
- 🎶 Tips
- 让你提升命令行效率的 Bash 快捷键 【完整版】
补充:ctrl + x, ctrl + e就地打开文本编辑器来编辑当前命令行,对于复杂命令行特别有用 - 应该知道的Linux技巧 | 酷 壳 - CoolShell
- 简洁的 Bash Programming 技巧 - 团子的小窝:Part 1 | Part 2 | Part 3
- Bash 测试和比较函数 —
test、[、[[、((、和if-then-else解密 - Filenames and Pathnames in Shell (bash, dash, ash, ksh, and so on): How to do it Correctly
- 理解 IFS - 团子的小窝
- shell中的IFS详解 – 笑遍世界
- Bash脚本:怎样一行行地读文件(最好和最坏的方法)
- Shell 脚本避免多次重复 source - 团子的小窝
- 一个奇怪的 echo 结果 - 团子的小窝
- 浅谈 Shell 脚本配置文件格式 - 团子的小窝
- Bash function 还能这么玩 - 团子的小窝
- Bash 获取当前函数名 - 团子的小窝
- Zsh和Bash,究竟有何不同 坑很深
- 让你提升命令行效率的 Bash 快捷键 【完整版】
- 💎 系统学习 — 看文章、了解Tips完全不能替代系统学习才能真正理解并专业开发!
- 《Bash Pocket Reference》
力荐!说明简单直接结构体系的佳作,专业Bash编程必备!且16年的第二版更新到了新版的Bash 4 - 《学习bash》 上面那本的展开版
- 官方资料
bash man| 中文版- Bash Reference Manual - gnu.org | 中文版
Bash参考手册,讲得全面且有深度,比如会全面地讲解不同转义的区别、命令的解析过程,这有助统一深入的方式认识Bash整个执行方式和过程。这些内容在其它书中往往不会讲(因为复杂难于深入浅出的讲解),但却一通百通的关键。
- Advanced Bash-Scripting Guide: An in-depth exploration of the art of shell scripting.
- 命令行的艺术 -
jlevy/the-art-of-command-line awesome-lists/awesome-bash: A curated list of delightful Bash scripts and resources.alebcay/awesome-shell: A curated list of awesome command-line frameworks, toolkits, guides and gizmos.- wzb56/13_questions_of_shell: shell十三问 - shell教程
- 实用 Shell 文档 - 团子的小窝
- 更多书籍参见个人整理的书籍豆列
Bash/Shell
- 《Bash Pocket Reference》
File: docs/install.md
🐌 下载使用
下载整个工程的脚本
直接clone工程
使用简单、方便更新,不过要安装有git。
git clone git://github.com/oldratlee/useful-scripts.git
cd useful-scripts
# 使用Release分支的内容
git checkout release-3.x
# 更新脚本
git pull包含2个分支:
dev-3.x:开发分支release-3.x:发布分支,功能稳定的脚本
PS:
我的做法是把useful-scripts checkout到$HOME/bin目录下,再把$HOME/bin/useful-scripts/bin配置到PATH变量上,这样方便我本地使用所有的脚本。
打包下载
下载文件release-3.x.zip:
wget --no-check-certificate https://github.com/oldratlee/useful-scripts/archive/release-3.x.zip
unzip release-3.x.zip下载和运行单个文件
`curl`文件直接用`bash`运行
curl -sLk 'https://raw.github.com/oldratlee/useful-scripts/release-3.x/bin/show-busy-java-threads' | bash下载单个文件
wget --no-check-certificate https://raw.github.com/oldratlee/useful-scripts/release-3.x/bin/show-busy-java-threads
chmod +x show-busy-java-threads
./show-busy-java-threadsFile: docs/java.md
🐌 `Java`相关脚本
关于Java排错与诊断,力荐️Arthas: ❤️
Arthas用户文档: https://arthas.aliyun.com/doc/quick-start.html- GitHub Repo: alibaba/arthas: Alibaba Java诊断利器
Arthas功能异常(😜)强劲,且在阿里巴巴线上支持使用多年。我自己也常用,一定要看看用用!
Arthas是通过Agent方式来连接运行的Java进程、主要通过交互式来完成功能,与之对应的脚本方式也有其优势,如:
- 可以在进程不能启动的情况下完成诊断(如依赖中的重复类分析、
ClassPath上的资源或类查找) - 开销少;简单少依赖(就纯文本的一个脚本文件)
- 方便与(已有的)工具(如
awk、sed、cron)、流程或设施集成,进一步编程/自动化
请按需按场景选用。
🍺 [show-busy-java-threads](../bin/show-busy-java-threads)
用于快速排查Java的CPU性能问题(top us值过高),自动查出运行的Java进程中消耗CPU多的线程,并打印出其线程栈,从而确定导致性能问题的方法调用。
目前只支持Linux。原因是Mac、Windows的ps命令不支持列出进程的线程id,更多信息参见 #33,欢迎提供解法。
PS,如何操作可以参见@bluedavy的《分布式Java应用》的【5.1.1 CPU消耗分析】一节,说得很详细:
top命令找出消耗CPU高的Java进程及其线程id:- 开启线程显示模式(
top -H,或是打开top后按H) - 按
CPU使用率排序(top缺省是按CPU使用降序,已经合要求;打开top后按P可以显式指定按CPU使用降序) - 记下
Java进程id及其CPU高的线程id
- 开启线程显示模式(
- 查看消耗
CPU高的线程栈:- 用进程
id作为参数,jstack出有问题的Java进程 - 手动转换线程
id成十六进制(可以用printf %x 1234) - 在
jstack输出中查找十六进制的线程id(可以用vim的查找功能/0x1234,或是grep 0x1234 -A 20)
- 用进程
- 查看对应的线程栈,分析问题
查问题时,会要多次上面的操作以分析确定问题,这个过程太繁琐太慢了。
期望整合上面的过程成一个脚本,这样一行命令就可以自动化地搞定。
用法
show-busy-java-threads
# 从所有运行的Java进程中找出最消耗CPU的线程(缺省5个),打印出其线程栈
# 缺省会自动从所有的Java进程中找出最消耗CPU的线程,这样用更方便
# 当然你可以通过 -p 选项 手动指定要分析的Java进程Id,以保证只会显示你关心的那个Java进程的信息
show-busy-java-threads -p <指定的Java进程Id>
show-busy-java-threads -p 42
show-busy-java-threads -p 42,47
show-busy-java-threads -c <要展示示的线程栈个数>
show-busy-java-threads <重复执行的间隔秒数> [<重复执行的次数>]
# 多次执行;这2个参数的使用方式类似vmstat命令
show-busy-java-threads -a <运行输出的记录到的文件>
# 记录到文件以方便回溯查看
show-busy-java-threads -S <存储jstack输出文件的目录>
# 指定jstack输出文件的存储目录,方便记录以后续分析
##############################
# 注意:
##############################
# 如果Java进程的用户 与 执行脚本的当前用户 不同,则jstack不了这个Java进程
# 为了能切换到Java进程的用户,需要加sudo来执行,即可以解决:
sudo show-busy-java-threads
show-busy-java-threads -s <指定jstack命令的全路径>
# 对于sudo方式的运行,JAVA_HOME环境变量不能传递给root,
# 而root用户往往没有配置JAVA_HOME且不方便配置,不能找到jstack命令。
# 这时显式指定jstack命令的路径就反而显得更方便了
# -m 选项:执行jstack命令时加上 -m 选项,显示上Native的栈帧,一般应用排查不需要使用
show-busy-java-threads -m
# -F 选项:执行jstack命令时加上 -F 选项(如果直接jstack无响应时,用于强制jstack),一般情况不需要使用
show-busy-java-threads -F
# -l 选项:执行jstack命令时加上 -l 选项,显示上更多相关锁的信息,一般情况不需要使用
# 注意:和 -m -F 选项一起使用时,可能会大大增加jstack操作的耗时
show-busy-java-threads -l
# 帮助信息
$ show-busy-java-threads -h
Usage: show-busy-java-threads [OPTION]... [delay [count]]
Find out the highest cpu consumed threads of java processes,
and print the stack of these threads.
Example:
show-busy-java-threads # show busy java threads info
show-busy-java-threads 1 # update every 1 second, (stop by eg: CTRL+C)
show-busy-java-threads 3 10 # update every 3 seconds, update 10 times
Output control:
-p, --pid <java pid(s)> find out the highest cpu consumed threads from
the specified java process.
support pid list(eg: 42,47).
default from all java process.
-c, --count <num> set the thread count to show, default is 5.
set count 0 to show all threads.
-a, --append-file <file> specifies the file to append output as log.
-S, --store-dir <dir> specifies the directory for storing
the intermediate files, and keep files.
default store intermediate files at tmp dir,
and auto remove after run. use this option to keep
files so as to review jstack/top/ps output later.
delay the delay between updates in seconds.
count the number of updates.
delay/count arguments imitates the style of
vmstat command.
jstack control:
-s, --jstack-path <path> specifies the path of jstack command.
-F, --force set jstack to force a thread dump.
use when jstack does not respond (process is hung).
-m, --mix-native-frames set jstack to print both java and
native frames (mixed mode).
-l, --lock-info set jstack with long listing.
prints additional information about locks.
CPU usage calculation control:
-i, --cpu-sample-interval specifies the delay between cpu samples to get
thread cpu usage percentage during this interval.
default is 0.5 (second).
set interval 0 to get the percentage of time spent
running during the *entire lifetime* of a process.
Miscellaneous:
-h, --help display this help and exit.
-V, --version display version information and exit.示例
$ show-busy-java-threads
[1] Busy(57.0%) thread(23355/0x5b3b) stack of java process(23269) under 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)
[2] Busy(26.1%) thread(24018/0x5dd2) stack of java process(23269) under 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)
at java.lang.Thread.run(Thread.java:662)
......上面的线程栈可以看出,CPU消耗最高的2个线程都在执行java.text.DateFormat.format,业务代码对应的方法是shared.monitor.schedule.AppMonitorDataAvgScheduler.run。可以基本确定:
AppMonitorDataAvgScheduler.run调用DateFormat.format次数比较频繁。DateFormat.format比较慢。(这个可以由DateFormat.format的实现确定。)
多执行几次show-busy-java-threads,如果上面情况高概率出现,则可以确定上面的判定。
因为调用越少代码执行越快,则出现在线程栈的概率就越低。
脚本有自动多次执行的功能,指定 重复执行的间隔秒数/重复执行的次数 参数。
分析shared.monitor.schedule.AppMonitorDataAvgScheduler.run实现逻辑和调用方式,以优化实现解决问题。
贡献者
- silentforce 改进此脚本,增加对环境变量
JAVA_HOME的判断。 #15 - liuyangc3
- superhj1987 / lirenzuo
- 提出/实现了多次执行的功能 superhj1987/awesome-scripts#1
- xiongchen2012 提出并解决了长用户名截断的Bug #62
- qsLI / sdslnmd
- 发现并提交Issue:show-busy-java-threads支持top来获取cpu占用率,ps的cpu占用率非实时 #67
- geekMessi
🍺 [show-duplicate-java-classes](../bin/show-duplicate-java-classes)
找出Java Lib(Java库,即Jar文件)或Class目录(类目录)中的重复类。
全系统支持(Python 3实现,安装Python 3即可),如Linux、Mac、Windows。
Java开发的一个麻烦的问题是Jar冲突(即多个版本的Jar),或者说重复类。会出NoSuchMethod等的问题,还不见得当时出问题。找出有重复类的Jar,可以防患未然。
用法
- 通过脚本参数 指定
Libs目录,查找目录下Jar文件,收集Jar文件中Class文件以分析重复类。可以指定多个Libs目录。- 缺省只会查找指定
Lib目录下Jar文件,不会收集Lib目录的子目录下Jar文件。- 因为
Libs目录一般不会用子目录再放Jar,也避免把去查找不期望的Jar文件。 - 可以通过
-L选项 设置 收集Lib子目录下的Jar文件;这样可以简化Lib目录的设置,不需要指定完整的Lib目录路径。
- 因为
- 对于找到的
Jar文件,缺省不会进一步收集包含在Jar文件中的Jar。- 即
FatJar/UberJar的场景,随着像SpringBoot的广泛使用,FatJar/UberJar也比较常见。 - 可以通过
-J选项 设置 收集包含在Jar文件中的Jar。
- 即
- 缺省只会查找指定
- 通过
-c选项 指定Class目录,直接收集这个目录下的Class文件以分析重复类。可以多次指定多个Class目录。
# 查找当前目录下所有Jar中的重复类
show-duplicate-java-classes
# 查找多个指定目录下所有Jar中的重复类
show-duplicate-java-classes path/to/lib_dir1 /path/to/lib_dir2
# 通过 -L 选项,收集子目录中的Jar文件
show-duplicate-java-classes -L path/to/lib_dir1
# 通过 -J 选项,收集包含在Jar文件中的Jar文件(即 收集包含在FatJar/UberJar中的Jar)
show-duplicate-java-classes -J path/to/lib_dir1
# 查找多个指定Class目录下的重复类。 Class目录 通过 -c 选项指定
show-duplicate-java-classes -c path/to/class_dir1 -c /path/to/class_dir2
# 查找指定Class目录和指定目录下所有Jar中的重复类的Jar
show-duplicate-java-classes path/to/lib_dir1 /path/to/lib_dir2 -c path/to/class_dir1 -c path/to/class_dir2
# 帮助信息
$ show-duplicate-java-classes -h
Usage: show-duplicate-java-classes [OPTION]... [-c class-dir1 [-c class-dir2] ...] [lib-dir1|jar-file1 [lib-dir2|jar-file2] ...]
Find duplicate classes among java lib dirs and class dirs.
Examples:
show-duplicate-java-classes # search jars from current dir
show-duplicate-java-classes path/to/lib_dir1 /path/to/lib_dir2
show-duplicate-java-classes -c path/to/class_dir1 -c /path/to/class_dir2
show-duplicate-java-classes -c path/to/class_dir1 path/to/lib_dir1
show-duplicate-java-classes -L path/to/lib_dir1
show-duplicate-java-classes -J path/to/lib_dir1
Options:
--version show program's version number and exit
-h, --help show this help message and exit
-L, --recursive-lib search jars in the sub-directories of lib dir
-J, --recursive-jar search jars in the jar file
-c CLASS_DIRS, --class-dir=CLASS_DIRS
add class dir
-R, --no-find-progress
do not display responsive find progress`JDK`开发场景使用说明
以Maven作为构建工程示意过程。
对于一般的工程
# 在项目模块目录下执行,拷贝依赖Jar到目录target/dependency下
$ mvn dependency:copy-dependencies -DincludeScope=runtime
...
# 检查重复类
$ show-duplicate-java-classes target/dependency
...对于`Web`工程
对于Web工程,即war maven模块,会打包生成war文件。
# 在war模块目录下执行,生成war文件
$ mvn install
...
# 解压war文件,war文件中包含了应用的依赖的Jar文件
$ unzip target/*.war -d target/war
...
# 检查重复类
$ show-duplicate-java-classes -c target/war/WEB-INF/classes target/war/WEB-INF/lib
...`Android`开发场景使用说明
Android开发,有重复类在编译打包时会报[Dex Loader] Unable to execute dex: Multiple dex files define Lorg/foo/xxx/Yyy。
但只会给出一个重复类名,如果重复类比较多时,上面打包/报错/排查会要进行多次,而Android的打包比较费时,这个过程比较麻烦,希望可以一次把所有重复类都列出来,一起排查掉。
以Gradle作为构建工程示意过程。
在App的build.gradle中添加拷贝库到目录build/dependencies下。
task copyDependencies(type: Copy) {
def dest = new File(buildDir, "dependencies")
// clean dir
dest.deleteDir()
dest.mkdirs()
// fill dir with dependencies
from configurations.compile into dest
}# 拷贝依赖
$ ./gradlew app:copyDependencies
...
# 检查重复类
$ show-duplicate-java-classes app/build/dependencies
...示例
$ show-duplicate-java-classes WEB-INF/lib
COOL! No duplicate classes found!
================================================================================
Find in 150 class paths:
================================================================================
1: (contain 9 classes) WEB-INF/lib/aopalliance-1.0.jar
2: (contain 25 classes) WEB-INF/lib/asm-5.0.4.jar
3: (contain 313 classes) WEB-INF/lib/aviator-5.0.0.jar
4: (contain 687 classes) WEB-INF/lib/cassandra-0.6.1.jar
...
$ show-duplicate-java-classes -c WEB-INF/classes WEB-INF/lib
Found 1272 duplicate classes in 345 class paths and 9 class path sets:
[1] found 188(100%) duplicate classes in 3 class paths:
1: (contain 188 classes) WEB-INF/lib/jdom-2.0.2.jar
2: (contain 195 classes) WEB-INF/lib/jdom2-2.0.6.jar
3: (contain 195 classes) WEB-INF/lib/jdom2-2.0.8.jar
[2] found 150(33.8%) duplicate classes in 2 class paths:
1: (contain 1385 classes) WEB-INF/lib/netty-all-4.0.35.Final.jar
2: (contain 444 classes) WEB-INF/lib/netty-common-4.1.31.Final.jar
[3] found 148(55.4%) duplicate classes in 2 class paths:
1: (contain 1385 classes) WEB-INF/lib/netty-all-4.0.35.Final.jar
2: (contain 267 classes) WEB-INF/lib/netty-handler-4.1.31.Final.jar
[4] found 103(82.4%) duplicate classes in 2 class paths:
1: (contain 125 classes) WEB-INF/lib/hessian-3.0.14.bugfix.jar
2: (contain 275 classes) WEB-INF/lib/hessian-4.0.38.jar
...
================================================================================
Duplicate classes detail info:
================================================================================
[1] found 188 duplicate classes in 3 class paths WEB-INF/lib/jdom-2.0.2.jar WEB-INF/lib/jdom2-2.0.6.jar WEB-INF/lib/jdom2-2.0.8.jar :
1: org/jdom2/Attribute.class
2: org/jdom2/AttributeList$1.class
3: org/jdom2/AttributeList$ALIterator.class
4: org/jdom2/AttributeList.class
5: org/jdom2/AttributeType.class
...
[2] found 150 duplicate classes in 2 class paths WEB-INF/lib/netty-all-4.0.35.Final.jar WEB-INF/lib/netty-common-4.1.31.Final.jar :
1: io/netty/util/AbstractReferenceCounted.class
2: io/netty/util/Attribute.class
3: io/netty/util/AttributeKey.class
4: io/netty/util/AttributeMap.class
5: io/netty/util/CharsetUtil.class
...
...
================================================================================
Find in 232 class paths:
================================================================================
1: (contain 42 classes) WEB-INF/classes
2: (contain 70 classes) WEB-INF/lib/HikariCP-2.7.8.jar
3: (contain 13 classes) WEB-INF/lib/accessors-smart-1.2.jar
4: (contain 9 classes) WEB-INF/lib/aopalliance-1.0.jar
5: (contain 25 classes) WEB-INF/lib/asm-5.0.4.jar
6: (contain 313 classes) WEB-INF/lib/aviator-5.0.0.jar
...贡献者
tgic 提供此脚本。友情贡献者的链接 commandlinefu.cn | 微博linux命令行精选
🍺 [find-in-jars](../bin/find-in-jars)
在当前目录下所有jar文件里,查找类或资源文件。
支持Linux、Mac、Windows(cygwin、MSSYS)。
用法
# 在当前目录下所有`jar`文件里,查找类或资源文件。
find-in-jars 'log4j\.properties'
find-in-jars 'log4j\.xml$'
find-in-jars log4j\\.xml$ # 和上面命令一样,Shell转义的不同写法而已
find-in-jars 'log4j\.(properties|xml)$'
# -d选项 指定 查找目录(覆盖缺省的当前目录)
find-in-jars 'log4j\.properties$' -d /path/to/find/directory
# 支持多个查找目录,多次指定这个选项即可
find-in-jars 'log4j\.properties' -d /path/to/find/directory1 -d /path/to/find/directory2
# -e选项 指定 查找`zip`文件的扩展名,缺省是`jar`
find-in-jars 'log4j\.properties' -e zip
# 支持多种查找扩展名,多次指定这个选项即可
find-in-jars 'log4j\.properties' -e jar -e zip
# -a选项 指定 查找结果中的Jar文件使用绝对路径
# 分享给别人时,Jar文件路径是完整的,方便别人找到文件
find-in-jars 'log4j\.properties' -a
# -s选项 指定 查找结果中的Jar文件和Jar文件里的查找Entry间分隔符,缺省是『!』
# 方便你喜欢的人眼查看,或是与工具脚本如`awk`的处理
find-in-jars 'log4j\.properties' -s ' <-> '
find-in-jars 'log4j\.properties' -s ' ' | awk '{print $2}'
# -l选项 指定 只列出Jar文件,不显示Jar文件内匹配的文件列表
# 列出 包含log4j.xml文件的Jar文件:
find-in-jars -l 'log4j\.xml$'
# 帮助信息
$ find-in-jars -h
Usage: find-in-jars [OPTION]... PATTERN
Find files in the jar files under specified directory,
search jar files recursively(include subdirectory).
The pattern default is *extended* regex.
Example:
find-in-jars 'log4j\.properties'
# search file log4j.properties/log4j.xml at zip root
find-in-jars '^log4j\.(properties|xml)$'
find-in-jars 'log4j\.properties$' -d /path/to/find/directory
find-in-jars '\.properties$' -d /path/to/find/dir1 -d path/to/find/dir2
find-in-jars 'Service\.class$' -e jar -e zip
find-in-jars 'Mon[^$/]*Service\.class$' -s ' <-> '
Find control:
-d, --dir the directory that find jar files.
default is current directory. this option can specify
multiply times to find in multiply directories.
-e, --extension set find file extension, default is jar. this option
can specify multiply times to find multiply extension.
-E, --extended-regexp PATTERN is an extended regular expression (*default*)
-F, --fixed-strings PATTERN is a set of newline-separated strings
-G, --basic-regexp PATTERN is a basic regular expression
-P, --perl-regexp PATTERN is a Perl regular expression
-i, --ignore-case ignore case distinctions
Output control:
-a, --absolute-path always print absolute path of jar file
-s, --separator specify the separator between jar file and zip entry.
default is `!'.
-L, --files-not-contained-found
print only names of JAR FILEs NOT contained found
-l, --files-contained-found
print only names of JAR FILEs contained found
-R, --no-find-progress do not display responsive find progress
Miscellaneous:
-h, --help display this help and exit
-V, --version display version information and exit注意,Pattern缺省是grep的 扩展正则表达式。
示例
# 在当前目录下的所有Jar文件中,查找出 log4j.properties文件
$ find-in-jars 'log4j\.properties$'
./hadoop-core-0.20.2-cdh3u3.jar!log4j.properties
......
# 查找出 以Service结尾的类,Jar文件路径输出成绝对路径
$ find-in-jars 'Service.class$' -a
/home/foo/deploy/app/WEB-INF/libs/spring-2.5.6.SEC03.jar!org/springframework/stereotype/Service.class
/home/foo/deploy/app/WEB-INF/libs/rpc-hello-0.0.1-SNAPSHOT.jar!com/taobao/biz/HelloService.class
......
# 在指定的多个目录的Jar文件中,查找出 properties文件
$ find-in-jars '\.properties$' -d WEB-INF/lib -d ../deploy/lib | grep -v '/pom\.properties$'
WEB-INF/lib/aspectjtools-1.6.2.jar!org/aspectj/ajdt/ajc/messages.properties
WEB-INF/lib/aspectjweaver-1.8.8.jar!org/aspectj/weaver/XlintDefault.properties
../deploy/lib/groovy-all-1.1-rc-1.jar!groovy/ui/InteractiveShell.properties
../deploy/lib/httpcore-4.3.3.jar!org/apache/http/version.properties
../deploy/lib/javax.servlet-api-3.0.1.jar!javax/servlet/http/LocalStrings_es.properties
......
# 列出 包含properties文件的Jar文件
$ find-in-jars '\.properties$' -l -d WEB-INF/lib
WEB-INF/lib/aspectjtools-1.6.2.jar
WEB-INF/lib/aspectjweaver-1.8.8.jar
WEB-INF/lib/javax.servlet-api-3.0.1.jar
......运行效果
支持彩色输出,文件名中的匹配部分以grep的高亮方式显示。
参考资料
在多个Jar(Zip)文件查找Log4J配置文件的Shell命令行
File: docs/logo.meta.txt
logo is created by https://www.logoly.pro
font: Zilla Slab
logo.fond-size: 60
logo-social.fond-size: 160
File: docs/shell.md
🐌 `Shell`相关脚本
`Shell`使用加强
🍺 [c](../bin/c)
原样命令行输出,并拷贝标准输出到系统剪贴板,省去CTRL+C操作,优化命令行与其它应用之间的操作流。
支持Linux、Mac、Windows(cygwin、MSSYS)。
命令名c的意思是Copy,因为这个命令我平时非常常用,所以使用一个字符的命令名,方便快速键入。
更多说明参见拷贝复制命令行输出放在系统剪贴板上。
用法/示例
有3种使用风格,根据需要或是你的偏好选取。
############################################################
# 1. 前缀方式,后面跟上要运行的命令
############################################################
$ c pwd
/Users/jerry
$ c echo -e 'a\nb'
a
b
# 这种使用方式,后面跟的命令不能是别名(alias),对于别名可以用下面的使用方式。
############################################################
# 2. 后缀方式,管道
############################################################
$ echo -e 'a\nb' | nl | c
1 a
2 b
# gb是oh-my-zsh的别名,列出git的分支,需要后缀的方式的使用。
$ gb | c
############################################################
# 3. 从标准输入读取内容。拷贝文件内容时这种方式最直接。
############################################################
$ c < ~/.ssh/id_rsa.pub
ssh-rsa EAAAABIwAAAQEAz+ETZEgoLeIiC0rjWewdDs0sbo8c...== [email protected]
############################################################
# -q选项:拷贝但不输出。
# 当输出内容比较多、又不关心输出内容和命令执行进展时,可以使用这个选项。
############################################################
$ c -q < ~/.ssh/id_rsa.pub
# 帮助信息
$ c --help
Usage: c [OPTION]... [command [command_args ...]]
Run command and put output to system clipper.
If no command is specified, read from stdin(pipe).
Example:
c grep -i 'hello world' menu.h main.c
set | c
c -q < ~/.ssh/id_rsa.pub
Options:
-k, --keep-eol do not trim new line at end of file
-q, --quiet suppress all normal output, default is false
-h, --help display this help and exit
-V, --version display version information and exit参考资料
- 拷贝复制命令行输出放在系统剪贴板上,给出了不同系统可用命令。
- 关于文本文件最后的换行,参见Why should text files end with a newline?
🍺 [coat](../bin/coat) and [taoc](../bin/taoc)
彩色cat/tac出文件行,方便人眼区分不同的行。
支持Linux、Mac、Windows(cygwin、MSSYS)。
命令支持选项、功能和使用方式与cat/tac命令完全一样。
文件操作在实现上完全代理给了cat/tac命令。
- 命令名
coat的意思是COlorful cAT;同时单词coat是外套,而彩色的输出行就像件漂亮的外套~ 🌈 😆 - 命令名
taoc是coat倒序拼写;命名方式就像tac之于cat。 🐈
用法/示例
$ echo Hello world | coat
Hello world
$ echo -e 'Hello\nWorld' | coat
Hello
World
$ echo -e 'Hello\nWorld' | taoc
World
Hello
$ echo -e 'Hello\nWorld' | nl | coat
1 Hello
2 World
$ coat file1 file2.txt
line1 of file1
line2 of file1
...
line1 of file2
line2 of file2
...
# 帮助信息
# 可以看到本人机器上实现代理的`cat`/`tac`命令是GNU的实现。
$ coat --help
Usage: coat [OPTION]... [FILE]...
cat lines colorfully.
Support options:
--help display this help and exit
--version output version information and exit
All other options and arguments are delegated to command cat,
more info see the help/man of command cat(e.g. cat --help).
cat executable: /usr/local/opt/coreutils/libexec/gnubin/cat
$ taoc --help
Usage: taoc [OPTION]... [FILE]...
tac lines colorfully.
Support options:
--help display this help and exit
--version output version information and exit
All other options and arguments are delegated to command tac,
more info see the help/man of command tac(e.g. tac --help).
tac executable: /usr/local/opt/coreutils/libexec/gnubin/tac注:上面示例中,没有彩色;在控制台上运行可以看出彩色效果,如下:
🍺 [a2l](../bin/a2l)
按行彩色输出参数,方便人眼查看。
支持Linux、Mac、Windows(cygwin、MSSYS)。
命令名a2l的意思是Arguments to(2) Lines。
用法/示例
$ a2l *.java
A.java
B.java
...
# zsh支持 **/* 跨目录glob,可以方便搜索,但是输出内容是空格分隔的不方便查看。
# 把参数按行输出方便查看 或是 grep
$ a2l **/*.sh
lib/console-text-color-themes.sh
test/parseOpts_test.sh
test/self-installer.sh
...注:上面示例中,没有彩色;在控制台上运行可以看出彩色效果,和上面的coat命令一样。
🍺 [uq](../bin/uq)
不重排序输入完成整个输入行的去重。相比系统的uniq命令加强的是可以跨行去重,不需要排序输入。
使用方式与支持的选项 模仿系统的uniq命令。支持Linux、Mac、Windows(cygwin、MSSYS)。
‼️ 注意: 去重过程会在内存持有整个输入(因为全局去重)!
对于输入大小较大的场景(如输入量有几G),需谨慎使用以避免占用过多内存;往往需要结合业务场景开发对应的优化实现。
虽然平时的大部分场景输入量非常有限(如几M),一个简单没有充分优化的实现是快速够用的。
uq处理的最大输入量缺省是 256m(字符数),超过了最大输入量则出错退出,以避免意外消耗了过大的内存;
可以通过-XM, --max-input选项 设置 消耗更多内存可接受的合理最大输入量,如uq --max-input 1g ...
因为系统的uniq命令去重相邻的行,需要组合sort命令以对整个输入去重,并且有下面的问题:
# 示例输入
$ cat foo.txt
c
c
b
a
a
c
c
$ uniq foo.txt
c
b
a
c
# c输出了2次,原因是第二个c与第一个c不是相邻的重复行
# 可以通过 sort -u 来完成整个输入去重,但这样操作,顺序与输入行不一致
$ sort -u foo.txt
a
b
c
# 输入行重排序了!
# 另外一个经典的用法 sort 与 uniq -c,输出重复次数
$ sort foo.txt | uniq -c
2 a
1 b
4 c
# 输入行重排序了!用法/示例
$ uq foo.txt # 输入是文件
$ cat foo.txt | uq # 或是 标准输入/管道
c
b
a
# 对整个输入行去重,且顺序与输入行一致(保留第一次出现的位置)
# -c 选项:输出重复次数
$ uq -c foo.txt
4 c
1 b
2 a
# -d, --repeated 选项:只输出 重复行
$ uq -d foo.txt
c
a
# -u, --unique 选项:只输出 唯一行(即不重复的行)
$ uq -u foo.txt
b
# -D 选项:重复行都输出,即重复了几次就输出几次
$ uq -D -c foo.txt
4 c
4 c
1 b
2 a
2 a
4 c
4 c
# 有多个文件参数时,最后一个参数 是 输出文件
$ uq in1.txt in2.txt out.txt
# 当有多个输入文件时,但要输出到控制台时,指定输出文件(最后一个文件参数)为 `-` 即可
$ uq in1.txt in2.txt -
# 如果消耗更多内存可接受的合理的,可以通过 -XM, --max-input 选项设置更大的最大输入量(缺省是256m)
$ uq -MI 768m large-file-input
$ uq --max-input 10g huge-file-input
# 帮助信息
$ uq -h
Usage: uq [OPTION]... [INPUT [OUTPUT]]
Filter lines from INPUT (or standard input), writing to OUTPUT (or standard output).
Same as `uniq` command in core utils,
but detect repeated lines that are not adjacent, no sorting required.
Example:
# only one file, output to stdout
uq in.txt
# more than 1 file, last file argument is output file
uq in.txt out.txt
# when use - as output file, output to stdout
uq in1.txt in2.txt -
Options:
-c, --count prefix lines by the number of occurrences
-d, --repeated only print duplicate lines, one for each group
-D print all duplicate lines
combined with -c/-d option usually
--all-repeated[=METHOD] like -D, but allow separating groups
with an empty line;
METHOD={none(default),prepend,separate}
-u, --unique Only output unique lines
that are not repeated in the input
-i, --ignore-case ignore differences in case when comparing
-z, --zero-terminated line delimiter is NUL, not newline
-XM, --max-input max input size(count by char), support k,m,g postfix
default is 256m
avoid consuming large memory unexpectedly
-h, --help display this help and exit
-V, --version display version information and exit🍺 [ap](../bin/ap) and [rp](../bin/rp)
批量转换文件路径为绝对路径/相对路径,会自动跟踪链接并规范化路径。
支持Linux、Mac、Windows(cygwin、MSSYS)。
命令名ap的意思是Absolute Path,rp是Relative Path。
用法/示例
# ap缺省打印当前路径的绝对路径
$ ap
/home/admin/useful-scripts/test
$ ap ..
/home/admin/useful-scripts
# 支持多个参数
$ ap .. ../.. /etc /etc/../etc
/home/admin/useful-scripts
/home/admin
/etc
/etc
# rp当一个参数时,打印相对于当前路径的相对路径
$ rp /home
../..
# 多于一个参数时,打印相对于最后一个参数的相对路径
$ rp /home /etc/../etc /home/admin
..
../../etc🍺 [cp-into-docker-run](../bin/cp-into-docker-run)
一个Docker使用的便利脚本。拷贝本机的执行文件到指定的docker container中并在docker container中执行。
支持Linux、Mac、Windows(cygwin、MSSYS)。
用法/示例
# 通过 -c 选项 指定 docker container
$ cp-into-docker-run -c container_foo /path/to/command command_args...
# 如果 指定的command 不是一个路径,会从 PATH 中查找
$ cp-into-docker-run -c container_foo a2l command_arg1 command_arg2
# 帮助信息
$ cp-into-docker-run -h
Usage: cp-into-docker-run [OPTION]... command [command-args]...
Copy the command into docker container
and run the command in container.
Example:
cp-into-docker-run -c container_foo command_copied_into_container command_arg1
docker options:
-c, --container destination docker container
-u, --docker-user docker username or UID to run command
optional, docker default is (maybe) root user
-w, --workdir absolute working directory inside the container
optional, docker default is (maybe) root dir
-t, --tmpdir tmp dir in docker to copy command
optional, default is /tmp
-p, --cp-path destination path in docker of the command(including file name)
if specified, command will be kept when run finished
optional, default is under tmp dir and deleted when run finished
run options:
-v, --verbose show operation step infos
miscellaneous:
-h, --help display this help and exit
-V, --version display version information and exit🍺 [tcp-connection-state-counter](../bin/tcp-connection-state-counter)
统计各个TCP连接状态的个数。
支持Linux、Mac、Windows(cygwin、MSSYS)。
像Nginx、Apache的机器上需要查看,TCP连接的个数,以判定
- 连接数、负荷
- 是否有攻击,查看
SYN_RECV数(SYN攻击) TIME_WAIT数,太多会导致TCP: time wait bucket table overflow。
用法/示例
$ tcp-connection-state-counter
CLOSE_WAIT 584
ESTABLISHED 493
TIME_WAIT 112
LISTEN 27
SYN_SENT 7贡献者
sunuslee 改进此脚本,增加对MacOS的支持。 #56
🍺 [xpl](../bin/xpl) and [xpf](../bin/xpf)
在命令行中快速完成 在文件浏览器中 打开/选中 指定的文件或文件夹的操作,优化命令行与其它应用之间的操作流。
支持Linux、Mac、Windows(cygwin、MSSYS)。
xpl:在文件浏览器中打开指定的文件或文件夹。xpl是explorer的缩写。xpf: 在文件浏览器中打开指定的文件或文件夹,并选中。xpf是EXplorer and select File的缩写。
用法/示例
xpl
# 缺省打开当前目录
xpl <文件或是目录>...
# 打开多个文件或目录
xpf
# 缺省打开当前目录
xpf <文件或是目录>...
# 打开多个文件或目录
# 示例
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贡献者
- Linhua Tan 修复Linux的选定Bug。
`Shell`开发/测试加强
🍺 [echo-args](../bin/echo-args)
在编写脚本时,常常要确认输入参数是否是期望的:参数个数,参数值(可能包含有人眼不容易发现的空格问题)。
支持Linux、Mac、Windows(cygwin、MSSYS)。
这个脚本输出脚本收到的参数。在控制台运行时,把参数值括起的括号显示成 红色,方便人眼查看。
用法/示例
$ ./echo-args 1 " 2 foo " "3 3"
0/3: [./echo-args]
1/3: [1]
2/3: [ 2 foo ]
3/3: [3 3]使用方式
需要查看某个脚本(实际上也可以是其它的可执行程序)输出参数时,可以这么做:
- 把要查看脚本重命名。
- 建一个
echo-args脚本的符号链接到要查看参数的脚本的位置,名字和查看脚本一样。
这样可以不改其它的程序,查看到输入参数的信息。
🍺 [console-text-color-themes.sh](../lib/console-text-color-themes.sh)
显示Terminator的全部文字彩色组合的效果及其打印方式。
支持Linux、Mac、Windows(cygwin、MSSYS)。
脚本中,也给出了colorEcho和colorEchoWithoutNewLine函数更方便输出彩色文本
用法
colorEcho <颜色样式> <要输出的文本>...
colorEchoWithoutNewLine <颜色样式> <要输出的文本>...示例
source console-text-color-themes.sh
# 输出红色文本
colorEcho "0;31;40" "Hello world!"
# 输出黄色带下划线的文本
colorEchoWithoutNewLine "4;33;40" "Hello world!" "Hello Hell!"运行效果
贡献者
姜太公 提供循环输出彩色组合的脚本。
参考资料
- utensil
的在Bash下输出彩色的文本,这是篇很有信息量很钻研的文章!
🍺 [parseOpts.sh](../lib/parseOpts.sh)
命令行选项解析库,加强支持选项有多个值(即数组)。
支持Linux、Mac、Windows(cygwin、MSSYS)。
自己写一个命令行选项解析函数,是因为bash的builtin命令getopts和加强版本命令getopt都不支持数组的值。
指定选项的多个值(即数组)的风格模仿find命令的-exec选项:
$ find . -name \*.txt -exec echo "find file: " {} \;
find file: foo.txt
find file: bar.txt
...用法
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-long 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) ,数组类型--的使用效果示例:
# 导入parseOpts.sh
source /path/to/parseOpts.sh
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
# 可以通过下面全局变量来获得解析的参数值:
# _OPT_VALUE_a = true
# _OPT_VALUE_a_long = true
# _OPT_VALUE_b = bv
# _OPT_VALUE_b_long = bv
# _OPT_VALUE_c 没有设置过
# _OPT_VALUE_c_long 没有设置过
# _OPT_ARGS = (--c-long c.sh -p pv -q qv arg1 ';' aa bb cc) ,数组类型兼容性
这个脚本比较复杂,测试过的环境有:
bash --versionGNU bash, version 4.1.5(1)-release (x86_64-pc-linux-gnu)uname -aLinux foo-host 2.6.32-41-generic #94-Ubuntu SMP Fri Jul 6 18:00:34 UTC 2012 x86_64 GNU/Linuxbash --versionGNU bash, version 3.2.53(1)-release (x86_64-apple-darwin14)uname -aDarwin 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 Darwinbash --versionGNU bash, version 3.00.15(1)-release (i386-redhat-linux-gnu)uname -aLinux foo-host 2.6.9-103.ELxenU #1 SMP Wed Mar 14 16:31:15 CST 2012 i686 i686 i386 GNU/Linux
贡献者
- Khotyn Huang 指出
bash3.0下使用有问题,并提供bash3.0的测试机器。
File: .github/dependabot.yml
To get started with Dependabot version updates, you'll need to specify which
package ecosystems to update and where the package manifests are located.
Please see the documentation for all configuration options:
https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: daily
File: .github/workflows/ci.yaml
Quickstart for GitHub Actions
https://docs.github.com/en/actions/quickstart
name: CI
on: [ push, pull_request, workflow_dispatch ]
jobs:
test:
runs-on: ${{ matrix.os }}
timeout-minutes: 5
strategy:
matrix:
# the OS supported by GitHub Actions
# https://docs.github.com/en/actions/using-github-hosted-runners/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources
os: [ ubuntu-latest, macos-latest ]
fail-fast: false
max-parallel: 64
name: Test on ${{ matrix.os }}
steps:
- uses: actions/checkout@v6
with:
submodules: recursive
- run: brew install coreutils gnu-sed
# https://docs.github.com/en/actions/learn-github-actions/variables#detecting-the-operating-system
# https://docs.github.com/en/actions/learn-github-actions/expressions
if: runner.os == 'macOS'
- run: test/chore/integration-test.sh
# https://remarkablemark.org/blog/2017/10/12/check-git-dirty/
- name: Check git dirty
run: |
git status --short
[ -z "$(git status --short)" ]File: .github/workflows/lint.yaml
Quickstart for GitHub Actions
https://docs.github.com/en/actions/quickstart
name: Lint
on: [ push, pull_request, workflow_dispatch ]
jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 5
name: Lint
steps:
- uses: actions/checkout@v6
with:
submodules: recursive
- run: test/chore/lint.sh
# https://remarkablemark.org/blog/2017/10/12/check-git-dirty/
- name: Check git dirty
run: |
git status --short
[ -z "$(git status --short)" ]