https://segmentfault.com/a/1190000041678641
原创:打码日记(微信公众号ID:codelogs),欢迎分享,转载请保留出处。
简介
网上有很多辅助开发的小工具,如base64,md5之类的,但这些小工具其实基本都可以用Linux命令实现,即方便又高效。
查看特殊字符
把这个放在首位,是因为这个实在太重要了,程序经常会因为特殊的看不见的字符而出现bug,因此一些本应该执行正确而实际出乎意料的字符串处理,你都应该看看是否含有特殊字符。
$ echo 'hello'|sed -n 'l' hello$ $ echo 'hello'|cat -A hello$ $ echo 'hello'|od -c 0000000 h e l l o \n 0000006
执行上面的命令会发现,echo会给输出加一个换行符。
查看字节数
当出现数据库字段超长错误时,这个命令会很有用,如oracle的varchar2(64)类型,表示最多存64字节,而业务插入的字符串是中英混合的,估计它有多少字节还挺麻烦。
$ echo -n 'hello,张三'|iconv -t utf-8|wc -c 12
时间戳转换
#日期串转时间戳 $ date -d '2020-06-08 00:13:28' +%s 1591546408 #时间戳转日期串 $ date -d '@1591546408' +"%F %T %z" 2020-06-08 00:13:28 +0800 #带时区版本,时区很重要,要时时刻刻注意 TZ='GMT-8' date -d '2020-06-08 00:13:28' +%s TZ='GMT-8' date -d '@1591546408' +"%F %T %z"
csv变json
#使用csvkit中的csvjson csvjson -y0 -I data.csv #使用python python -c "import csv,json;print(json.dumps(list(csv.reader(open('data.csv')))))"
文件服务器
python3 -m http.server 8000
urlencode,base64,md5,sha256
做开发经常会用到这些。
# urlencode,建议添加为别名 $ alias urlencode='python3 -c "import sys;from urllib import request as rq;print(rq.quote(sys.argv[1],safe=\"\"))"' $ urlencode 你好 %E4%BD%A0%E5%A5%BD # urldecode,建议添加为别名 $ alias urldecode='python3 -c "import sys;from urllib import request as rq;print(rq.unquote(sys.argv[1]))"' $ urldecode '%E4%BD%A0%E5%A5%BD' 你好 # base64编解码 $ echo hello |base64 -w0 aGVsbG8K $ echo aGVsbG8K|base64 -d hello # md5摘要 $ echo hello |md5sum b1946ac92492d2347c6235b4d2611184 - # sha256摘要 $ echo hello | sha256sum 5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03 - # hmacWithSha256摘要 $ echo hello | hmac256 'secret' 171b5670f7b4037fb90bef773b022130e48100fdd40ea023730097da9a68f4ff
json格式化
$ echo '{"id":1,"name":"lisi"}' | jq . { "id": 1, "name": "lisi" }
字符串escape与unescape
#将"转成\" $ echo 'hi,"lisi"' | jq -R 'tojson' -r "hi,\"lisi\"" #将\"转成" $ echo '"hi,\"lisi\""' | jq -R 'fromjson' -r hi,"lisi" #json属性值里是json内容,不知你有没有遇到过这种蹩脚设计 $ echo '{"code":200,"data":"{\"id\":1,\"name\":\"lisi\"}"}' | jq '.data=(.data|fromjson)' { "code": 200, "data": { "id": 1, "name": "lisi" } }
unicode编码
开发时,也经常需要在汉字与\u4f60
形式之间转换,下面这些命令就很有用了。
#unicode解码 $ echo -e '\u4f60\u597d' 你好 $ echo $'\u4f60\u597d' 你好 $ echo '\u4f60\u597d'|sed 's/\\u//g'|xxd -r -ps|iconv -f ucs-2be 你好 #unicode编码 $ echo -n '你好'|iconv -t ucs-2be|xxd -ps|sed -E 's/.{4}/\\u&/g' \u4f60\u597d #转换文件编码为utf8,也很有用 enconv -L zh_CN -c -x UTF-8 file.txt
生成随机密码
#生成随机密码 $ openssl rand -hex 16 fb9f47a7ebad6bd77be332d6b3a0bc0b $ cat /dev/urandom |head -c 16|xxd -ps eb297181cad546210a00118d543b78bf $ cat /dev/urandom |tr -dc A-Za-z0-9 |head -c 32 V1NB2Oc1mCJ3mNfofDZCQB68dRde30Xz #生成10以内随机数 awk -v b=$(cat /dev/urandom|tr -dc 0-9|head -c 9) 'BEGIN{srand(b);print int(rand()*10)}' cat /dev/urandom|head -c 4|od -An -t u4 --endian=big|awk '{print int($1/2^32*10)}' #生成uuid $ uuidgen 7b45c1c2-0533-45e5-9903-802ee58b6638
ip地址转数字
众所周知,ip地址实际是一个4字节的数字,如果把ip以数字的形式保存在数据库中,可以节省空间。
#ip转数字 $ echo 192.168.0.1|tr . '\n'|xargs printf "%02X"|xxd -r -ps|od -An -t u4 --endian=big 3232235521 #数字转ip $ printf "%08X" 3232235521|xxd -r -ps |od -An -t u1 192 168 0 1
进制转换
#printf可以实现十进制到十六进制的转换 $ printf "%08X" 3232235521 C0A80001 #bc可以实现任意进制之间互转 $ echo C0A80001|sed 's/^/obase=10;ibase=16;/g'|bc 3232235521 $ echo C0A80001|sed 's/^/obase=2;ibase=16;/g'|bc 11000000101010000000000000000001
查看ascii
#直接查看man文档 man ascii #用od查看 printf "%0.2X" {0..127}| xxd -r -ps | od -t x1d1ca
搜索内容
在搜索日志时,tac通常比cat更有用,比如我们搜索最近产生的10次异常。
tac app.log|grep -iw -B 20 -m 10 'exception'|tac
另外,当不知道要找的内容在当前目录下的那个文件中时,应该优先使用grep -rn搜索一把,比如忘记了tomcat的端口在哪配置。
grep -rn -w 8080 .
查看进程日志
当你进入一个陌生的服务器环境,不知道java进程产生的日志文件在哪,与其问别人,不如直接自己找。
#使用lsof pid=`pidof java` lsof -p $pid|grep .log$ #lsof不可用时,试试这个 ls -l /proc/$pid/fd |grep .log$
反向shell
有时,需要别人帮忙排查问题,但又不想把服务器密码告诉别人,这时可以给别人一个反向shell。
#获取shell端 socat file:`tty`,rawer TCP-LISTEN:9999,bind=0.0.0.0,reuseaddr,keepalive,keepcnt=3,keepidle=600,keepintvl=600,pf=ip4 #给出shell端 nohup socat system:'stty rows 63 columns 207;bash -li',pty,stderr,setsid,sigint,sane,ctty TCP:192.168.0.1:9999 &
统计行数
# 统计行数 wc -l sed -n '$=' # 分组统计行数 uniq -c
生成连续时间片
生成连续时间片,一般用在脚本中,比如查询一年的数据量,当数据量很大时,直接查询是出不来结果的,这时可以把1年拆成1天天的,让查询1天天的跑。
如下,1年拆成1天天时间范围的sql,丢到mysql命令里慢慢查。
generate_day_range(){ seq $(date -d '2022-01-01' +%s) $((24*3600)) $(date -d '2022-02-01' +%s) | sed '1!{$!p}' | paste - - } query_one_day(){ begin_time=$(date -d "@$1" +'%F %T') end_time=$(date -d "@$2" +'%F %T') sql="select count(*) from order where create_time >= '${begin_time}' and create_time < '${end_time}'; "; echo "$sql" mysql -N -e "$sql" } export -f query_one_day generate_day_range | xargs -l -P2 bash -c 'query_one_day "$@"' -
pv显示进度与速度控制
长时间运行的脚本,看不到进度让人很着急,于是就有了pv命令。
如cp命令,本身没有显示进度功能,复制大文件干瞪眼,这时可以使用pv命令代替。
pv file1 > file2
如上节查询1年数据量的脚本,要查看执行进度,只需要在mysql命令前放入pv命令即可。
generate_day_query_sql(){ fmt='select count(*) from order where create_time >= "%s" and create_time < "%s"; \n'; seq 0 $1 \ |xargs -i date -d "2021-01-01 00:00:00 {} days" +'%F %T' \ |sed '1!{$!p}' \ |paste - - \ |awk -F'\t' -v fmt="$fmt" '{printf fmt,$1,$2}' } # -l表示计算流过pv的行数,pv默认计算流过的字节 # -s指定总行数,这样每一行文本流过pv,pv就能计算出当前进度了 generate_day_query_sql 365 | pv -l -s 365 | mysql -vvv
pv还能用来控制速度,这样就能避免脚本把数据库查挂了。
# -L 2表示文本流过速度不超过每秒2行 generate_day_query_sql 365 | pv -l -s 365 -L 2 | mysql -vvv
对比表结构
相同系统,不同环境的数据库,保持一致表结构其实是比较困难的,当需要找出他们的不同点时,尽量不要一个个字段去对比,效率太低了。
#导出db1中所有表名 echo 'show tables' | mysql --skip-column-names -D db1 > table_names.txt #导出db1与db2的表结构 cat table_names.txt | sed 's/.*/show create table &;/' | tee >(mysql -D db1 > db1_tables.txt) >(mysql -D db2 > db2_tables.txt) #恢复换行符 sed -i 's/\\n/\n/g' db1_tables.txt db2_tables.txt #对比表结构 icdiff db1_tables.txt db2_tables.txt
总结
可以将这些工具命令添加为Linux别名,用熟练后,你会发现你根本离不开它。
往期内容
Linux文本命令技巧(下)
Linux文本命令技巧(上)
原来awk真是神器啊
好用的parallel命令
常用网络命令总结