利用Linux Shell脚本实现SSR自动更换端口——沙洲
最近不知道为什么突然查的特别严,可能是战疫期间境外反动势力异常猖獗,刚换完端口不到三天新端口又被封了。苦于手动换端口、换IP实在令人不胜厌烦,我突发奇想能不能使用传说中强大实用的bash脚本实现自动换端口呢,由于我在这方面完全是个一窍不通的小白,因此编写脚本期间很是吃了一番苦头,参考了很多很多前辈的文章,本文特此记录。
本文深受以下文章启发,可作为参考:
首先墙裂推荐==跑不了的你兄==的这篇文章,内容十分详细:
Linux下使用脚本读取参数修改配置文件 —— 跑不了的你。
可惜文章内容实在比较深,小的理解起来比较困难,但是可以树立在这方面需用到的命令的一个较的全面认识。关于文章中用到但并未详细解释的opts,这篇文章有十分详细的叙述:
shell脚本中关于getopts的使用方法 —— 邻家大男孩
基础的Shell脚本格式与如何执行:
Linux就该这么学 —— 执行Shell脚本(多种方法)
学习如何用awk命令读取文件中的内容:
awk命令 —— DBA_zzher
Shell awk命令详解(格式+使用方法)
关于学习用复杂的sed命令来替换文件内容:
Linux命令行大全 —— sed命令
linux sed命令详解(推荐)
如何在脚本里实现算术:
详解Shell编程之变量数值计算(一)
如何截取部分字符串:
Linux-shell脚本字符串截取 —— linux运维菜
以及下面一些写得非常好,但是因为和实际情况暂不符所以暂未用上的文章,留作参考:
shell脚本读取ini配置文件的值 —— yuzaipiaofei
Linux Shell环境下用jq命令处理json文件 —— 东孤熊猫
查询IP或者端口是否被封
- IP被封
IP被封的情况比较好鉴别,直连ping一下服务器的ip看下是否有响应就行了。Ctrl+R打开运行,输入cmd,然后ping MY_IP。 - 端口被封
这里推荐一个网站,可以从全球不同地方的服务器ping访问指定的端口。对于位于境外的服务器来说,输入ip:端口号,如果国内ip访问显示是红色的,那么代表该端口就被封了。
端口ping检查
从SSR配置文件中读取端口号
通常来说Linux下的配置文件为ini文件,因此可参考上述 yuzaipiaofei的文章进行编写。但是不巧我的配置文件是userconfig.json
,东孤熊猫的文章中描述的jq命令来读取json文件的值固然十分方便,但是十分不巧的是我的vps上的debian连apt-get都404,完全装不了jq。因此需要想办法手动从userconfig.json
读取到当前的端口号是多少。
awk命令简介
这里我选择了使用awk
命令。借花献佛简单记录下awk
,awk
命令包含两部分,模式(pattern)与动作(action),其中动作又分为格式化输出和流程控制两类。
awk
命令的格式:awk '条件1{动作1}条件2{动作2}条件3{动作3}...' 文件名
- 条件
一般使用关系表达式作为条件,表示对于awk
命令的执行条件进行限制。这些关系表达式非常多,具体参考表1。
条件类型 | 条件 | 说明 |
---|---|---|
awk保留字 | BEGIN | 在 awk 程序一开始,尚未读取任何数据之前执行。BEGIN 后的动作只在程序开始时执行一次 |
awk保留字 | END | 在 awk 程序处理完所有数据,即将结束时执行。END 后的动作只在程序结束时执行一次 |
关系运算符 | > | 大于 |
关系运算符 | < | 小于 |
关系运算符 | >= | 大于等于 |
关系运算符 | <= | 小于等于 |
关系运算符 | == | 等于 |
关系运算符 | != | 不等于 |
关系运算符 | A~B | 判断字符串 A 中是否包含能匹配 B 表达式的子字符串 |
关系运算符 | A!~B | 判断字符串 A 中是否不包含能匹配 B 表达式的子字符串 |
正则表达式 | /正则/ | 如果在“//”中可以写入字符,则也可以支持正则表达式 |
- 动作
- 流程控制
流程控制比较复杂,可以作为一门单独的语言讲解,这里请参考Shell awk命令详解(格式+使用方法) - 格式化输出
[root@localhost ~]# awk '{printf $2 "\t" $6 "\n"}' student.txt
#输出第二列和第六列的内容
Name Average
Liming 87.66
Sc 85.66
Gao 91.66
在这个例子中没有设定任何的条件类型,所以这个文件中的所有内容都符合条件,动作会无条件执行。动作是格式化输出 printf
,"$2"
和"$6"
分别代表第二个字段和第六个字段,所以这条 awk
命令会列出 student.txt
文件的第二个字段和第六个字段。
如果想让 awk 识别字符串,则必须使用"//"包含,例如:
[root@localhost ~]$ awk '/Liming/ {print}' student.txt
#打印Liming的成绩
1 Liming 82 95 86 87.66
然后基于这个原理我对ssr的配置文件userconfig.json
文件进行截取。首选查看配置文件的具体格式root@vultr:~# vim /etc/shadowsocksr/userconfig.json
,看见服务器端口是由server_port这个字段记录的:
{
"server": "0.0.0.0",
"server_ipv6": "::",
"server_port": 8994, #ssr服务器端口
"local_address": "127.0.0.1",
"local_port": 1080,
"password": "@********6", #ssr密码
"method": "aes-256-cfb",
"protocol": "auth_sha1_v4_compatible",
"protocol_param": "",
"obfs": "plain",
"obfs_param": "",
"speed_limit_per_con": 0,
"speed_limit_per_user": 0,
"additional_ports" : {},
"timeout": 120,
"udp_timeout": 60,
"dns_ipv6": false,
"connect_verbose_info": 0,
"redirect": "",
"fast_open": false
}
因为awk
命令默认是用:进行字段分隔的,所以我们通过正则表达式的格式化输出条件,输出该行的第二个字段,命令如下:
awk '/"server_port"/{printf $2 "\n"}' /etc/shadowsocksr/user-config.json
执行结果:
awk命令执行结果.png
这样子就得到了我们需要的旧端口号啦。
端口号进行自增运算
得到8994,
后,我们需要用语法将逗号去掉,${var%,*}
表示从右数起的第一个逗号,保留它之前的所有内容,然后我们就port=${var%,*}
得到了port=8994。
然而此时有一个新的问题,我们截取出来的port现在是个字符串,而shell中是字符串数字是不能进行运算的。
在下对Shell脚本不甚了解,苦于没有像Java中Integer.parseInt(port)
这种方便的语法,试验了很久查了很多资料,终于成功把它转变为了数字。其实说来非常简单,只要用$[]
就行了,网上很多资料真是毁人不倦!
然后我们用$(( ))
的命令表示其中的内容是进行数学运算,这样子就成功实现了端口号的自增:
newport=$[port]
newport=$(($newport + 1))
现在echo $newport
输出就是数值的8994了!。
用新端口替换旧端口
既然得到了新的端口,接下来我们就用sed
命令来替换旧端口,sed
命令是一个面向字符流的非交互式编辑器。在sed
中s
表示替换、-i
表示直接修改源文件。
说实话,sed
真是太复杂晦涩了,也可能是在下没有找到好的参考资料,总之一直弄不对。搞了好久,一直在报ed: -e expression #1, char 35: unterminated `s' command
的错误,迫于无奈,这里直接采用最简单的实现方式,今后再慢慢对其进行研究:
sed -i "s/$port/$newport/" /etc/shadowsocksr/user-config.json
这行命令表示用找到源文件中所有$port
即8994的地方,一律替换成$newport
的值8995。s/...
表示采用替换命令,而-i
表示将这种替换直接作用于源文件而不是在控制台打印。幸好user-config.json
文件中只有一个字段是8994,否则这种实现方式后果不堪设想,整个文件所有的8994字段被修改,今后应用它必须慎之又慎!
验证脚本
综上,我们的bash文件如下:
#!/bin/bash
ssr_file=/etc/shadowsocksr/user-config.json
cp ${ssr_file} ${ssr_file}.bk
var=$(awk '/"server_port"/{printf $2 "\n"}' ${ssr_file})
echo "old port is ${var%,*}"
port=${var%,*}
newport=$[port]
newport=$(($newport + 1))
newport=$(echo $newport)
sed -i "s/$port/$newport/" ${ssr_file}
var=$(awk '/"server_port"/{printf $2 "\n"}' ${ssr_file})
echo "new port is ${var%,*}"
cat ${ssr_file}
结束编辑,运行bash。可以看见执行结果:
运行结果.png
到这里我们用shell脚本实现SSR自动换端口就结束了,如果您觉得本文对您有所帮助,请按个赞吧,谢谢 !: )
网友评论