背景
我们在 Linux
命令行中,经常会需要使用代理(参考:How To Use Proxy Server To Access Internet at Shell Prompt With http_proxy Variable ,Linux Proxy Server Settings – Set Proxy For Command Line ),以便能访问某些资源。
在我使用 Clash 开启了一个代理,端口为 7890
后,我常常用下面的 shell
代码在命令行中启用或取消代理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 # 可以把代码写入 bash 和 zsh 的启动文件中,新开 session 中可用 # cat >> ~/.bashrc >> ~/.zshrc << 'EOF' export proxy=localhost:7890 # 如果是在 WSL 中,可以替换为下面的语句 # export proxy=$(cat /etc/resolv.conf | grep -m 1 nameserver | awk '{ print $2 }' ):7890;# proxy+ 命令用于启用代理 alias proxy+='\ export https_proxy=http://$proxy export http_proxy=http://$proxy export all_proxy=socks5://$proxy export no_proxy=localhost,127.0.0.1,::1 echo "proxy has been set to: $proxy" curl ipinfo.io'; # proxy- 命令用于停用代理 alias proxy-='\ unset http_proxy https_proxy all_proxy no_proxy echo "proxy has been cleared"; curl ipinfo.io'; # EOF
为了便于做到这一点,我从自己的偏好出发,编写了一个 shell
脚本,已经在 bash
和 zsh
中通过测试。
代码实现
TIPS 代码的最新版本在 GitHub Gist 中维护
https://gist.github.com/ChenyangGao/b5abf2de8bb5a91753764f9403adcc99
文件名称为 mod-proxy.sh
,代码中端口的默认值 PROXY_PORT
设为 7890,是 Clash 的默认端口,实现如下:
mod-proxy.sh 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 # ? 设置代理 ip,请运行 proxy # AUTHOR='ChenyangGao <https://chenyanggao.github.io/>' ' # VERSION=0.2 if [ -n "${MOD_PROXY_sourced+x}" ]; then return 0 fi # inetutils (apt) # net-tools (yum) -proxy-get-local-ipv4-using-hostname() { hostname -I 2>&- | awk '{print $1}' } # iproute2 -proxy-get-local-ipv4-using-iproute2() { # OR ip route get 1.2.3.4 | awk '{print $7}' ip -4 route 2>&- | awk '{print $NF}' | grep -Eo --color=never '[0-9]+(\.[0-9]+){3}' } # net-tools -proxy-get-local-ipv4-using-ifconfig() { ( ifconfig 2>&- || ip addr show 2>&- ) | grep -Eo '^\s+inet\s+\S+' | grep -Eo '[0-9]+(\.[0-9]+){3}' | grep -Ev '127\.0\.0\.1|0\.0\.0\.0' } # 获取本机 IPv4 地址 -proxy-get-local-ipv4() { set -o pipefail -proxy-get-local-ipv4-using-hostname || -proxy-get-local-ipv4-using-iproute2 || -proxy-get-local-ipv4-using-ifconfig } -proxy-get-local-ipv4-select() { local ips=$(-proxy-get-local-ipv4) local retcode=$? if [ $retcode -ne 0 ]; then return $retcode fi grep -m 1 "^192\." <<<"$ips" || \ grep -m 1 "^172\." <<<"$ips" || \ grep -m 1 "^10\." <<<"$ips" || \ head -n 1 <<<"$ips" } -proxy-get-remote-ssh-ip-using-ssh-env() { ( [ -n "$SSH_CLIENT" ] && awk '{print $1}' <<<"$SSH_CLIENT" ) || \ ( [ -n "$SSH_CONNECTION" ] && awk '{print $1}' <<<"$SSH_CONNECTION" ) } -proxy-get-remote-ssh-ip-using-who() { who am i 2>&- | awk '{print $NF}' | grep '([^)]\+)' | grep -o '[^()]\+' } # 获取远程连接到本机的 ssh 客户端的 ip 地址 -proxy-get-remote-ssh-ip() { -proxy-get-remote-ssh-ip-using-ssh-env || -proxy-get-remote-ssh-ip-using-who } # 默认的代理服务的主机地址,可以是 ip 或 域名 PROXY_HOST=$(( -proxy-get-local-ipv4-select | head -n 1 ) || echo 127.0.0.1) # 默认的代理端口(clash 的默认端口是 7890),0-65535 之间的数字 PROXY_PORT=7890 -proxy-format-proxy() { if [ -z "$1" ]; then echo "$PROXY_HOST:$PROXY_PORT" elif [[ $1 == \[* ]]; then # as ipv6 if [[ $1 == *\] ]]; then # as without port echo "$1:$PROXY_PORT" else # as with port echo "$1" fi elif [[ $1 =~ ^[0-9]+(\.[0-9]+){3}$ ]]; then # as ipv4 (without port) echo "$1:$PROXY_PORT" elif [[ $1 =~ ^:[0-9]+$ ]]; then # as bare port echo "$PROXY_HOST$1" elif [[ $1 == *:*:* && $1 =~ ^[0-9a-zA-Z:]+$ ]]; then # as ipv6 (without port) echo "[$1]:$PROXY_PORT" elif [[ $1 != *:* ]]; then # as hostname without port echo "$1:$PROXY_PORT" else # no op, here may be a mistake echo "$1" fi } # 在 shell 中启用代理,默认采用本机上的 7890 端口的代理服务 proxy-set() { local proxy=$(-proxy-format-proxy "$1") export https_proxy=http://$proxy export http_proxy=http://$proxy export all_proxy=socks5://$proxy export no_proxy='localhost,127.0.0.1,::1' echo "proxy has been set to: $proxy" ## Get public ip in Linux command line ## NOTE curl ≈ wget -qO - # curl api.ipify.org # curl checkip.amazonaws.com # curl cip.cc # curl httpbin.org/ip # curl ifconfig.cat # ipv6 # curl ifconfig.co # ipv6 # curl ifconfig.io # ipv6 # curl ifconfig.me # curl ifconfig.net # ipv6 # curl inet-ip.info # curl ipinfo.io # 👍 # curl ipv4.icanhazip.com # curl ipv4.ident.me # curl ipv4.ip.gs # curl ipv4.ip.sb # curl ip-api.com # 👍 # curl ip.threep.top # curl ipecho.net/plain # curl myip.dnsomatic.com # 👎 # curl myip.ipip.net # curl https://checkipv4.dedyn.io # curl https://ip.tool.lu # dig +short myip.opendns.com @resolver1.opendns.com # dig ANY +short @resolver2.opendns.com myip.opendns.com curl ipinfo.io } alias proxy+=proxy-set # 在 shell 中启用代理,代理服务来自 ssh 连接到这台机器的远程机器(仅适用于局域网) proxy-set-from-remote() { -proxy-get-remote-ssh-ip 1>&- && proxy-set $(-proxy-get-remote-ssh-ip) } alias proxy++=proxy-set-from-remote # 在 shell 中停用代理 proxy-clear() { unset http_proxy https_proxy all_proxy no_proxy echo 'proxy has been cleared' curl ipinfo.io } alias proxy-=proxy-clear # 打印 export 命令,用于启用 shell 中的代理(来自这台机器,命令可在局域网中的其他机器上使用) proxy-export() { local proxy=$(-proxy-format-proxy "$1") echo "\ # 在 shell 中启用代理,命令可在局域网中的其他机器上使用 export https_proxy=http://$proxy export http_proxy=http://$proxy export all_proxy=socks5://$proxy export no_proxy='localhost,127.0.0.1,::1' # 用以下命令停用代理 # unset http_proxy https_proxy all_proxy no_proxy" } alias proxy@=proxy-export # 打印 alias 命令,用于启用和停用 shell 中的代理(来自这台机器,命令可在局域网中的其他机器上使用),其中: # proxy+ 在 shell 中启用代理 # proxy- 在 shell 中停用代理 proxy-alias() { local proxy=$(-proxy-format-proxy "$1") cat << EOF # 在 shell 中启用代理,命令可在局域网中的其他机器上使用 alias proxy+="\ export https_proxy=http://$proxy export http_proxy=http://$proxy export all_proxy=socks5://$proxy export no_proxy='localhost,127.0.0.1,::1' echo 'proxy has been set to: $proxy' curl ipinfo.io" # 在 shell 中停用代理,命令可在局域网中的其他机器上使用 alias proxy-="\ unset http_proxy https_proxy all_proxy no_proxy echo 'proxy has been cleared' curl ipinfo.io" EOF } alias proxy@@=proxy-alias alias proxy#='echo "\ [环境变量] PROXY_HOST 默认的代理服务的主机地址,可以是 ip 或 域名 PROXY_PORT 默认的代理端口(clash 和 ssr(shadowsocksR,酸酸乳) 等科学上网软件的默认端口是 7890),0-65535 之间的数字 ---------------------------------------- [命令] proxy# 输出使用说明 proxy+ 在 shell 中启用代理,默认采用本机上的 7890 端口(clash 和 ssr 等科学上网软件的默认端口)的代理服务。如果要指定端口,运行形如 PROXY_PORT=<port> proxy+ proxy++ 在 shell 中启用代理,代理服务来自 ssh 连接到这台机器的远程机器(仅适用于局域网)。如果要指定端口,运行形如 PROXY_PORT=<port> proxy++ proxy- 停用 shell 中的代理 proxy@ 打印 export 命令,用于启用 shell 中的代理(来自这台机器,命令可在局域网中的其他机器上使用) proxy@@ 打印 alias 命令,用于启用和停用 shell 中的代理(来自这台机器,命令可在局域网中的其他机器上使用)"' MOD_PROXY_sourced=
使用说明
假设上面的代码位于 /path/to/mod-proxy.sh
。要加载这个脚本,就在命令行运行如下命令
1 source /path/to/mod-proxy.sh
或者修改当前用户所用 shell
的配置文件,对于 bash
就是 ∼/.bashrc
,对于 zsh
就是 ∼/.zshrc
。把上面的命令添加到对应的配置文件中去。
打印帮助信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 $ proxy [环境变量] PROXY_HOST 默认的代理服务的主机地址,可以是 ip 或 域名 PROXY_PORT 默认的代理端口(clash 和 ssr(shadowsocksR,酸酸乳) 等科学上网软件的默认端口是 7890),0-65535 之间的数字 ---------------------------------------- [命令] proxy# 输出使用说明 proxy+ 在 shell 中启用代理,默认采用本机上的 7890 端口(clash 和 ssr 等科学上网软件的默认端口)的代理服务。如果要指定端口,运行形如 PROXY_PORT=<port> proxy+ proxy++ 在 shell 中启用代理,代理服务来自 ssh 连接到这台机器的远程机器(仅适用于局域网)。如果要指定端口,运行形如 PROXY_PORT=<port> proxy++ proxy- 停用 shell 中的代理 proxy@ 打印 export 命令,用于启用 shell 中的代理(来自这台机器,命令可在局域网中的其他机器上使用) proxy@@ 打印 alias 命令,用于启用和停用 shell 中的代理(来自这台机器,命令可在局域网中的其他机器上使用)
打印 export 命令,在局域网的某台机器上启用本机上代理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 # 可接受 1 个参数,用于指定 host:port。如果要单独指定 host,写作 host;如果要单独指定 port,写作 :port;如果省略参数,则用 $PROXY_HOST :$PROXY_PORT 。 $ proxy@ # 在 shell 中启用代理,命令可在局域网中的其他机器上使用 export https_proxy=http://192.168.1.2:7890 export http_proxy=http://192.168.1.2:7890 export all_proxy=socks5://192.168.1.2:7890 export no_proxy='localhost,127.0.0.1,::1' # 用以下命令停用代理 # unset http_proxy https_proxy all_proxy no_proxy $ proxy@ 192.168.1.66 # 在 shell 中启用代理,命令可在局域网中的其他机器上使用 export https_proxy=http://192.168.1.66:7890 export http_proxy=http://192.168.1.66:7890 export all_proxy=socks5://192.168.1.66:7890 export no_proxy='localhost,127.0.0.1,::1' # 用以下命令停用代理 # unset http_proxy https_proxy all_proxy no_proxy
上述命令输出几个 export
命令,可以在同一局域网中的任何 Linux
机器的命令行中运行,即可启用代理。
如果要取消代理,在那台机器的命令行中运行
1 unset http_proxy https_proxy all_proxy no_proxy
打印 alias 命令,在局域网的某台机器上启用和停用本机上代理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 # 可接受 1 个参数,用于指定 host:port。如果要单独指定 host,写作 host;如果要单独指定 port,写作 :port;如果省略参数,则用 $PROXY_HOST :$PROXY_PORT 。 $ proxy@@ # 在 shell 中启用代理,命令可在局域网中的其他机器上使用 alias proxy+="export https_proxy=http://192.168.1.2:7890 export http_proxy=http://192.168.1.2:7890 export all_proxy=socks5://192.168.1.2:7890 export no_proxy='localhost,127.0.0.1,::1' echo 'proxy has been set to: 192.168.1.2:7890' curl ipinfo.io" # 在 shell 中停用代理,命令可在局域网中的其他机器上使用 alias proxy-="unset http_proxy https_proxy all_proxy no_proxy echo 'proxy has been cleared' curl ipinfo.io" $ proxy@@ 192.168.1.66 # 在 shell 中启用代理,命令可在局域网中的其他机器上使用 alias proxy+="export https_proxy=http://192.168.1.66:7890 export http_proxy=http://192.168.1.66:7890 export all_proxy=socks5://192.168.1.66:7890 export no_proxy='localhost,127.0.0.1,::1' echo 'proxy has been set to: 192.168.1.66:7890' curl ipinfo.io" # 在 shell 中停用代理,命令可在局域网中的其他机器上使用 alias proxy-="unset http_proxy https_proxy all_proxy no_proxy echo 'proxy has been cleared' curl ipinfo.io"
上述命令可输出 2 个 alias 命令,可以在同一局域网中的任何 Linux
机器的命令行中运行,以生成别名:
proxy+
在 shell
中启用代理
1 2 3 4 5 6 7 8 9 10 11 12 $ proxy+ proxy has been set to: 192.168.1.2:7890 { "ip": "103.47.100.220", "city": "Sham Shui Po", "region": "Sham Shui Po", "country": "HK", "loc": "22.3302,114.1595", "org": "AS38136 Akari Networks", "timezone": "Asia/Hong_Kong", "readme": "https://ipinfo.io/missingauth" }
proxy-
在 shell 中停用代理
1 2 3 4 5 6 7 8 9 10 11 12 $ proxy- proxy has been cleared { "ip": "111.3.34.208", "city": "Shanghai", "region": "Shanghai", "country": "CN", "loc": "31.2222,121.4581", "org": "AS56041 China Mobile communications corporation", "timezone": "Asia/Shanghai", "readme": "https://ipinfo.io/missingauth" }
shell 命令:proxy+
、proxy++
和 proxy-
proxy+
在 shell 中启用本机上代理
1 2 3 4 5 6 7 8 9 10 11 12 13 # 可接受 1 个参数,用于指定 host:port。如果要单独指定 host,写作 host;如果要单独指定 port,写作 :port;如果省略参数,则用 $PROXY_HOST :$PROXY_PORT 。 $ proxy+ proxy has been set to: 192.168.1.2:7890 { "ip": "103.47.100.220", "city": "Sham Shui Po", "region": "Sham Shui Po", "country": "HK", "loc": "22.3302,114.1595", "org": "AS38136 Akari Networks", "timezone": "Asia/Hong_Kong", "readme": "https://ipinfo.io/missingauth" }
proxy++
在 shell 中启用远程代理,代理服务来自 ssh 连接到这台机器的远程机器(仅适用于局域网)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 $ proxy++ proxy has been set to: 192.168.1.66:7890 { "ip": "103.47.100.220", "city": "Sham Shui Po", "region": "Sham Shui Po", "country": "HK", "loc": "22.3302,114.1595", "org": "AS38136 Akari Networks", "timezone": "Asia/Hong_Kong", "readme": "https://ipinfo.io/missingauth" } $ PROXY_PORT=1234 proxy++ proxy has been set to: 192.168.1.66:1234 { "ip": "103.47.100.220", "city": "Sham Shui Po", "region": "Sham Shui Po", "country": "HK", "loc": "22.3302,114.1595", "org": "AS38136 Akari Networks", "timezone": "Asia/Hong_Kong", "readme": "https://ipinfo.io/missingauth" }
proxy-
在 shell 中停用本机上代理
1 2 3 4 5 6 7 8 9 10 11 12 $ proxy- proxy has been cleared { "ip": "111.3.34.208", "city": "Shanghai", "region": "Shanghai", "country": "CN", "loc": "31.2222,121.4581", "org": "AS56041 China Mobile communications corporation", "timezone": "Asia/Shanghai", "readme": "https://ipinfo.io/missingauth" }