问题原因

我可以理解,开发人员不想使用苹果使用的旧bash v3。但从用户的帖子来看,安装一个较新的bash并不那么好

所以我看了wireguard的wg-quick。需要支持的唯一变化,两个bash版本都是为了摆脱关联数组SERVICE_DNS,并处理v3的BASHPID。

解决方案

那么就有了一下的操作

diff --git a/src/tools/wg-quick/darwin.bash b/src/tools/wg-quick/darwin.bash
index 30f3541..170caed 100755
--- a/src/tools/wg-quick/darwin.bash
+++ b/src/tools/wg-quick/darwin.bash
@@ -38,8 +38,6 @@ die() {
exit 1
} -[[ ${BASH_VERSINFO[0]} -ge 4 ]] || die "Version mismatch: bash ${BASH_VERSINFO[0]} detected, when bash 4+ required"
-
CONFIG_SEARCH_PATHS=( /etc/wireguard /usr/local/etc/wireguard ) parse_options() {
@@ -200,22 +198,37 @@ collect_endpoints() {
done < <(wg show "$REAL_INTERFACE" endpoints)
} -declare -A SERVICE_DNS
+declare -a SERVICE_DNS_KEY
+declare -a SERVICE_DNS_VAL
+
collect_new_service_dns() {
+ local old_key old_val
local service get_response
- local -A found_services
+ local idx
+
+ old_key=("${SERVICE_DNS_KEY[@]}")
+ old_val=("${SERVICE_DNS_VAL[@]}")
+ SERVICE_DNS_KEY=()
+ SERVICE_DNS_VAL=()
{ read -r _ && while read -r service; do
[[ $service == "*"* ]] && service="${service:1}"
- found_services["$service"]=1
- [[ -n ${SERVICE_DNS["$service"]} ]] && continue
- get_response="$(cmd networksetup -getdnsservers "$service")"
- [[ $get_response == *" "* ]] && get_response="Empty"
- [[ -n $get_response ]] && SERVICE_DNS["$service"]="$get_response"
+ get_response=""
+ for idx in "${!old_key[@]}"; do
+ if [[ $service = ${old_key[$idx]} ]]; then
+ get_response="${old_val[$idx]}"
+ unset old_key[$idx]
+ break
+ fi
+ done
+ if [[ -z $get_response ]]; then
+ get_response="$(cmd networksetup -getdnsservers "$service")"
+ [[ $get_response == *" "* ]] && get_response="Empty"
+ fi
+ if [[ -n $get_response ]]; then
+ SERVICE_DNS_KEY+=("$service")
+ SERVICE_DNS_VAL+=("$get_response")
+ fi
done; } < <(networksetup -listallnetworkservices)
-
- for service in "${!SERVICE_DNS[@]}"; do
- [[ -n ${found_services["$service"]} ]] || unset SERVICE_DNS["$service"]
- done
} set_endpoint_direct_route() {
@@ -272,7 +285,7 @@ set_endpoint_direct_route() {
set_dns() {
collect_new_service_dns
local service response
- for service in "${!SERVICE_DNS[@]}"; do
+ for service in "${SERVICE_DNS_KEY[@]}"; do
while read -r response; do
[[ $response == *Error* ]] && echo "$response" >&2
done < <(cmd networksetup -setdnsservers "$service" "${DNS[@]}")
@@ -280,11 +293,11 @@ set_dns() {
} del_dns() {
- local service response
- for service in "${!SERVICE_DNS[@]}"; do
+ local idx response
+ for idx in "${!SERVICE_DNS_KEY[@]}"; do
while read -r response; do
[[ $response == *Error* ]] && echo "$response" >&2
- done < <(cmd networksetup -setdnsservers "$service" ${SERVICE_DNS["$service"]} || true)
+ done < <(cmd networksetup -setdnsservers "${SERVICE_DNS_KEY[$idx]}" ${SERVICE_DNS_VAL[$idx]} || true)
done
} @@ -292,6 +305,7 @@ monitor_daemon() {
echo "[+] Backgrounding route monitor" >&2
(trap 'del_routes; del_dns; exit 0' INT TERM EXIT
exec >/dev/null 2>&1
+ [[ ${BASH_VERSINFO[0]} -ge 4 ]] || BASHPID=$(sh -c 'echo $PPID')
local event pid=$BASHPID
[[ ${#DNS[@]} -gt 0 ]] && trap set_dns ALRM
# TODO: this should also check to see if the endpoint actually changes

完整脚本

#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
#
# Copyright (C) 2015-2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
# set -e -o pipefail
shopt -s extglob
export LC_ALL=C SELF="${BASH_SOURCE[0]}"
[[ $SELF == */* ]] || SELF="./$SELF"
SELF="$(cd "${SELF%/*}" && pwd -P)/${SELF##*/}"
export PATH="/usr/bin:/bin:/usr/sbin:/sbin:${SELF%/*}:$PATH" WG_CONFIG=""
INTERFACE=""
ADDRESSES=( )
MTU=""
DNS=( )
DNS_SEARCH=( )
TABLE=""
PRE_UP=( )
POST_UP=( )
PRE_DOWN=( )
POST_DOWN=( )
SAVE_CONFIG=0
CONFIG_FILE=""
PROGRAM="${0##*/}"
ARGS=( "$@" ) cmd() {
echo "[#] $*" >&2
"$@"
} die() {
echo "$PROGRAM: $*" >&2
exit 1
} # [[ ${BASH_VERSINFO[0]} -ge 4 ]] || die "Version mismatch: bash ${BASH_VERSINFO[0]} detected, when bash 4+ required" CONFIG_SEARCH_PATHS=( /etc/wireguard /opt/homebrew/etc/wireguard ) parse_options() {
local interface_section=0 line key value stripped path v
CONFIG_FILE="$1"
if [[ $CONFIG_FILE =~ ^[a-zA-Z0-9_=+.-]{1,15}$ ]]; then
for path in "${CONFIG_SEARCH_PATHS[@]}"; do
CONFIG_FILE="$path/$1.conf"
[[ -e $CONFIG_FILE ]] && break
done
fi
[[ -e $CONFIG_FILE ]] || die "\`$CONFIG_FILE' does not exist"
[[ $CONFIG_FILE =~ (^|/)([a-zA-Z0-9_=+.-]{1,15})\.conf$ ]] || die "The config file must be a valid interface name, followed by .conf"
CONFIG_FILE="$(cd "${CONFIG_FILE%/*}" && pwd -P)/${CONFIG_FILE##*/}"
((($(stat -f '0%#p' "$CONFIG_FILE") & $(stat -f '0%#p' "${CONFIG_FILE%/*}") & 0007) == 0)) || echo "Warning: \`$CONFIG_FILE' is world accessible" >&2
INTERFACE="${BASH_REMATCH[2]}"
shopt -s nocasematch
while read -r line || [[ -n $line ]]; do
stripped="${line%%\#*}"
key="${stripped%%=*}"; key="${key##*([[:space:]])}"; key="${key%%*([[:space:]])}"
value="${stripped#*=}"; value="${value##*([[:space:]])}"; value="${value%%*([[:space:]])}"
[[ $key == "["* ]] && interface_section=0
[[ $key == "[Interface]" ]] && interface_section=1
if [[ $interface_section -eq 1 ]]; then
case "$key" in
Address) ADDRESSES+=( ${value//,/ } ); continue ;;
MTU) MTU="$value"; continue ;;
DNS) for v in ${value//,/ }; do
[[ $v =~ (^[0-9.]+$)|(^.*:.*$) ]] && DNS+=( $v ) || DNS_SEARCH+=( $v )
done; continue ;;
Table) TABLE="$value"; continue ;;
PreUp) PRE_UP+=( "$value" ); continue ;;
PreDown) PRE_DOWN+=( "$value" ); continue ;;
PostUp) POST_UP+=( "$value" ); continue ;;
PostDown) POST_DOWN+=( "$value" ); continue ;;
SaveConfig) read_bool SAVE_CONFIG "$value"; continue ;;
esac
fi
WG_CONFIG+="$line"$'\n'
done < "$CONFIG_FILE"
shopt -u nocasematch
} detect_launchd() {
unset LAUNCHED_BY_LAUNCHD
local line
while read -r line; do
if [[ $line =~ ^\s*domain\ =\ ]]; then
LAUNCHED_BY_LAUNCHD=1
break
fi
done < <(launchctl procinfo $$ 2>/dev/null)
} read_bool() {
case "$2" in
true) printf -v "$1" 1 ;;
false) printf -v "$1" 0 ;;
*) die "\`$2' is neither true nor false"
esac
} auto_su() {
[[ $UID == 0 ]] || exec sudo -p "$PROGRAM must be run as root. Please enter the password for %u to continue: " -- "$BASH" -- "$SELF" "${ARGS[@]}"
} get_real_interface() {
local interface diff
wg show interfaces >/dev/null
[[ -f "/var/run/wireguard/$INTERFACE.name" ]] || return 1
interface="$(< "/var/run/wireguard/$INTERFACE.name")"
[[ -n $interface && -S "/var/run/wireguard/$interface.sock" ]] || return 1
diff=$(( $(stat -f %m "/var/run/wireguard/$interface.sock" 2>/dev/null || echo 200) - $(stat -f %m "/var/run/wireguard/$INTERFACE.name" 2>/dev/null || echo 100) ))
[[ $diff -ge 2 || $diff -le -2 ]] && return 1
REAL_INTERFACE="$interface"
echo "[+] Interface for $INTERFACE is $REAL_INTERFACE" >&2
return 0
} add_if() {
export WG_TUN_NAME_FILE="/var/run/wireguard/$INTERFACE.name"
mkdir -p "/var/run/wireguard/"
cmd "${WG_QUICK_USERSPACE_IMPLEMENTATION:-wireguard-go}" utun
get_real_interface
} del_routes() {
[[ -n $REAL_INTERFACE ]] || return 0
local todelete=( ) destination gateway netif
while read -r destination _ _ _ _ netif _; do
[[ $netif == "$REAL_INTERFACE" ]] && todelete+=( "$destination" )
done < <(netstat -nr -f inet)
for destination in "${todelete[@]}"; do
cmd route -q -n delete -inet "$destination" >/dev/null || true
done
todelete=( )
while read -r destination gateway _ netif; do
[[ $netif == "$REAL_INTERFACE" || ( $netif == lo* && $gateway == "$REAL_INTERFACE" ) ]] && todelete+=( "$destination" )
done < <(netstat -nr -f inet6)
for destination in "${todelete[@]}"; do
cmd route -q -n delete -inet6 "$destination" >/dev/null || true
done
for destination in "${ENDPOINTS[@]}"; do
if [[ $destination == *:* ]]; then
cmd route -q -n delete -inet6 "$destination" >/dev/null || true
else
cmd route -q -n delete -inet "$destination" >/dev/null || true
fi
done
} del_if() {
[[ -z $REAL_INTERFACE ]] || cmd rm -f "/var/run/wireguard/$REAL_INTERFACE.sock"
cmd rm -f "/var/run/wireguard/$INTERFACE.name"
} up_if() {
cmd ifconfig "$REAL_INTERFACE" up
} add_addr() {
if [[ $1 == *:* ]]; then
cmd ifconfig "$REAL_INTERFACE" inet6 "$1" alias
else
cmd ifconfig "$REAL_INTERFACE" inet "$1" "${1%%/*}" alias
fi
} set_mtu() {
# TODO: use better set_mtu algorithm from freebsd.bash
local mtu=0 current_mtu=-1 destination netif defaultif
if [[ -n $MTU ]]; then
cmd ifconfig "$REAL_INTERFACE" mtu "$MTU"
return
fi
while read -r destination _ _ _ _ netif _; do
if [[ $destination == default ]]; then
defaultif="$netif"
break
fi
done < <(netstat -nr -f inet)
[[ -n $defaultif && $(ifconfig "$defaultif") =~ mtu\ ([0-9]+) ]] && mtu="${BASH_REMATCH[1]}"
[[ $mtu -gt 0 ]] || mtu=1500
mtu=$(( mtu - 80 ))
[[ $(ifconfig "$REAL_INTERFACE") =~ mtu\ ([0-9]+) ]] && current_mtu="${BASH_REMATCH[1]}"
[[ $mtu -eq $current_mtu ]] || cmd ifconfig "$REAL_INTERFACE" mtu "$mtu"
} collect_gateways() {
local destination gateway GATEWAY4=""
while read -r destination gateway _; do
[[ $destination == default && $gateway != "link#"* ]] || continue
GATEWAY4="$gateway"
break
done < <(netstat -nr -f inet) GATEWAY6=""
while read -r destination gateway _; do
[[ $destination == default && $gateway != "link#"* ]] || continue
GATEWAY6="$gateway"
break
done < <(netstat -nr -f inet6)
} collect_endpoints() {
ENDPOINTS=( )
while read -r _ endpoint; do
[[ $endpoint =~ ^\[?([a-z0-9:.]+)\]?:[0-9]+$ ]] || continue
ENDPOINTS+=( "${BASH_REMATCH[1]}" )
done < <(wg show "$REAL_INTERFACE" endpoints)
} declare -a SERVICE_DNS_KEY
declare -a SERVICE_DNS_VAL
declare -a SERVICE_DNS_SEARCH
collect_new_service_dns() {
local old_key old_val
local service get_response
local idx old_key=("${SERVICE_DNS_KEY[@]}")
old_val=("${SERVICE_DNS_VAL[@]}")
SERVICE_DNS_KEY=()
SERVICE_DNS_VAL=()
{ read -r _ && while read -r service; do
[[ $service == "*"* ]] && service="${service:1}"
get_response=""
for idx in "${!old_key[@]}"; do
if [[ $service = ${old_key[$idx]} ]]; then
get_response="${old_val[$idx]}"
unset old_key[$idx]
break
fi
done
if [[ -z $get_response ]]; then
get_response="$(cmd networksetup -getdnsservers "$service")"
[[ $get_response == *" "* ]] && get_response="Empty"
fi
if [[ -n $get_response ]]; then
SERVICE_DNS_KEY+=("$service")
SERVICE_DNS_VAL+=("$get_response")
fi
done; } < <(networksetup -listallnetworkservices)
} set_endpoint_direct_route() {
local old_endpoints endpoint old_gateway4 old_gateway6 remove_all_old=0 added=( )
old_endpoints=( "${ENDPOINTS[@]}" )
old_gateway4="$GATEWAY4"
old_gateway6="$GATEWAY6"
collect_gateways
collect_endpoints [[ $old_gateway4 != "$GATEWAY4" || $old_gateway6 != "$GATEWAY6" ]] && remove_all_old=1 if [[ $remove_all_old -eq 1 ]]; then
for endpoint in "${ENDPOINTS[@]}"; do
[[ " ${old_endpoints[*]} " == *" $endpoint "* ]] || old_endpoints+=( "$endpoint" )
done
fi for endpoint in "${old_endpoints[@]}"; do
[[ $remove_all_old -eq 0 && " ${ENDPOINTS[*]} " == *" $endpoint "* ]] && continue
if [[ $endpoint == *:* && $AUTO_ROUTE6 -eq 1 ]]; then
cmd route -q -n delete -inet6 "$endpoint" >/dev/null 2>&1 || true
elif [[ $AUTO_ROUTE4 -eq 1 ]]; then
cmd route -q -n delete -inet "$endpoint" >/dev/null 2>&1 || true
fi
done for endpoint in "${ENDPOINTS[@]}"; do
if [[ $remove_all_old -eq 0 && " ${old_endpoints[*]} " == *" $endpoint "* ]]; then
added+=( "$endpoint" )
continue
fi
if [[ $endpoint == *:* && $AUTO_ROUTE6 -eq 1 ]]; then
if [[ -n $GATEWAY6 ]]; then
cmd route -q -n add -inet6 "$endpoint" -gateway "$GATEWAY6" >/dev/null || true
else
# Prevent routing loop
cmd route -q -n add -inet6 "$endpoint" ::1 -blackhole >/dev/null || true
fi
added+=( "$endpoint" )
elif [[ $AUTO_ROUTE4 -eq 1 ]]; then
if [[ -n $GATEWAY4 ]]; then
cmd route -q -n add -inet "$endpoint" -gateway "$GATEWAY4" >/dev/null || true
else
# Prevent routing loop
cmd route -q -n add -inet "$endpoint" 127.0.0.1 -blackhole >/dev/null || true
fi
added+=( "$endpoint" )
fi
done
ENDPOINTS=( "${added[@]}" )
} set_dns() {
collect_new_service_dns
local service response
for service in "${SERVICE_DNS_KEY[@]}"; do
while read -r response; do
[[ $response == *Error* ]] && echo "$response" >&2
done < <(
cmd networksetup -setdnsservers "$service" "${DNS[@]}"
if [[ ${#DNS_SEARCH[@]} -eq 0 ]]; then
cmd networksetup -setsearchdomains "$service" Empty
else
cmd networksetup -setsearchdomains "$service" "${DNS_SEARCH[@]}"
fi
)
done
} del_dns() {
local idx response
for idx in "${!SERVICE_DNS_KEY[@]}"; do
while read -r response; do
[[ $response == *Error* ]] && echo "$response" >&2
# done < <(
# cmd networksetup -setdnsservers "$service" ${SERVICE_DNS["$service"]} || true
# cmd networksetup -setsearchdomains "$service" ${SERVICE_DNS_SEARCH["$service"]} || true
# )
done < <(cmd networksetup -setdnsservers "${SERVICE_DNS_KEY[$idx]}" ${SERVICE_DNS_VAL[$idx]} || true)
done
} monitor_daemon() {
echo "[+] Backgrounding route monitor" >&2
(trap 'del_routes; del_dns; exit 0' INT TERM EXIT
exec >/dev/null 2>&1
exec 19< <(exec route -n monitor)
[[ ${BASH_VERSINFO[0]} -ge 4 ]] || BASHPID=$(sh -c 'echo $PPID')
local event bpid=$BASHPID mpid=$!
[[ ${#DNS[@]} -gt 0 ]] && trap set_dns ALRM
# TODO: this should also check to see if the endpoint actually changes
# in response to incoming packets, and then call set_endpoint_direct_route
# then too. That function should be able to gracefully cleanup if the
# endpoints change.
while read -u 19 -r event; do
[[ $event == RTM_* ]] || continue
ifconfig "$REAL_INTERFACE" >/dev/null 2>&1 || break
[[ $AUTO_ROUTE4 -eq 1 || $AUTO_ROUTE6 -eq 1 ]] && set_endpoint_direct_route
[[ -z $MTU ]] && set_mtu
if [[ ${#DNS[@]} -gt 0 ]]; then
set_dns
sleep 2 && kill -ALRM $bpid 2>/dev/null &
fi
done
kill $mpid) &
[[ -n $LAUNCHED_BY_LAUNCHD ]] || disown
} add_route() {
[[ $TABLE != off ]] || return 0 local family=inet
[[ $1 == *:* ]] && family=inet6 if [[ $1 == */0 && ( -z $TABLE || $TABLE == auto ) ]]; then
if [[ $1 == *:* ]]; then
AUTO_ROUTE6=1
cmd route -q -n add -inet6 ::/1 -interface "$REAL_INTERFACE" >/dev/null
cmd route -q -n add -inet6 8000::/1 -interface "$REAL_INTERFACE" >/dev/null
else
AUTO_ROUTE4=1
cmd route -q -n add -inet 0.0.0.0/1 -interface "$REAL_INTERFACE" >/dev/null
cmd route -q -n add -inet 128.0.0.0/1 -interface "$REAL_INTERFACE" >/dev/null
fi
else
[[ $TABLE == main || $TABLE == auto || -z $TABLE ]] || die "Darwin only supports TABLE=auto|main|off"
[[ $(route -n get "-$family" "$1" 2>/dev/null) =~ interface:\ $REAL_INTERFACE$'\n' ]] || cmd route -q -n add -$family "$1" -interface "$REAL_INTERFACE" >/dev/null fi
} set_config() {
cmd wg setconf "$REAL_INTERFACE" <(echo "$WG_CONFIG")
} save_config() {
local old_umask new_config current_config address cmd
new_config=$'[Interface]\n'
while read -r address; do
[[ $address =~ inet6?\ ([^ ]+) ]] && new_config+="Address = ${BASH_REMATCH[1]}"$'\n'
done < <(ifconfig "$REAL_INTERFACE")
# TODO: actually determine current DNS for interface
for address in "${DNS[@]}"; do
new_config+="DNS = $address"$'\n'
done
[[ -n $MTU ]] && new_config+="MTU = $MTU"$'\n'
[[ -n $TABLE ]] && new_config+="Table = $TABLE"$'\n'
[[ $SAVE_CONFIG -eq 0 ]] || new_config+=$'SaveConfig = true\n'
for cmd in "${PRE_UP[@]}"; do
new_config+="PreUp = $cmd"$'\n'
done
for cmd in "${POST_UP[@]}"; do
new_config+="PostUp = $cmd"$'\n'
done
for cmd in "${PRE_DOWN[@]}"; do
new_config+="PreDown = $cmd"$'\n'
done
for cmd in "${POST_DOWN[@]}"; do
new_config+="PostDown = $cmd"$'\n'
done
old_umask="$(umask)"
umask 077
current_config="$(cmd wg showconf "$REAL_INTERFACE")"
trap 'rm -f "$CONFIG_FILE.tmp"; exit' INT TERM EXIT
echo "${current_config/\[Interface\]$'\n'/$new_config}" > "$CONFIG_FILE.tmp" || die "Could not write configuration file"
sync "$CONFIG_FILE.tmp"
mv "$CONFIG_FILE.tmp" "$CONFIG_FILE" || die "Could not move configuration file"
trap - INT TERM EXIT
umask "$old_umask"
} execute_hooks() {
local hook
for hook in "$@"; do
hook="${hook//%i/$REAL_INTERFACE}"
hook="${hook//%I/$INTERFACE}"
echo "[#] $hook" >&2
(eval "$hook")
done
} cmd_usage() {
cat >&2 <<-_EOF
Usage: $PROGRAM [ up | down | save | strip ] [ CONFIG_FILE | INTERFACE ] CONFIG_FILE is a configuration file, whose filename is the interface name
followed by \`.conf'. Otherwise, INTERFACE is an interface name, with
configuration found at:
${CONFIG_SEARCH_PATHS[@]/%//INTERFACE.conf}.
It is to be readable by wg(8)'s \`setconf' sub-command, with the exception
of the following additions to the [Interface] section, which are handled
by $PROGRAM: - Address: may be specified one or more times and contains one or more
IP addresses (with an optional CIDR mask) to be set for the interface.
- DNS: an optional DNS server to use while the device is up.
- MTU: an optional MTU for the interface; if unspecified, auto-calculated.
- Table: an optional routing table to which routes will be added; if
unspecified or \`auto', the default table is used. If \`off', no routes
are added. Besides \`auto' and \`off', only \`main' is supported on
this platform.
- PreUp, PostUp, PreDown, PostDown: script snippets which will be executed
by bash(1) at the corresponding phases of the link, most commonly used
to configure DNS. The string \`%i' is expanded to INTERFACE.
- SaveConfig: if set to \`true', the configuration is saved from the current
state of the interface upon shutdown. See wg-quick(8) for more info and examples.
_EOF
} cmd_up() {
local i
get_real_interface && die "\`$INTERFACE' already exists as \`$REAL_INTERFACE'"
trap 'del_if; del_routes; exit' INT TERM EXIT
execute_hooks "${PRE_UP[@]}"
add_if
set_config
for i in "${ADDRESSES[@]}"; do
add_addr "$i"
done
set_mtu
up_if
for i in $(while read -r _ i; do for i in $i; do [[ $i =~ ^[0-9a-z:.]+/[0-9]+$ ]] && echo "$i"; done; done < <(wg show "$REAL_INTERFACE" allowed-ips) | sort -nr -k 2 -t /); do
add_route "$i"
done
[[ $AUTO_ROUTE4 -eq 1 || $AUTO_ROUTE6 -eq 1 ]] && set_endpoint_direct_route
[[ ${#DNS[@]} -gt 0 ]] && set_dns
monitor_daemon
execute_hooks "${POST_UP[@]}"
trap - INT TERM EXIT
} cmd_down() {
if ! get_real_interface || [[ " $(wg show interfaces) " != *" $REAL_INTERFACE "* ]]; then
die "\`$INTERFACE' is not a WireGuard interface"
fi
execute_hooks "${PRE_DOWN[@]}"
[[ $SAVE_CONFIG -eq 0 ]] || save_config
del_if
execute_hooks "${POST_DOWN[@]}"
} cmd_save() {
if ! get_real_interface || [[ " $(wg show interfaces) " != *" $REAL_INTERFACE "* ]]; then
die "\`$INTERFACE' is not a WireGuard interface"
fi
save_config
} cmd_strip() {
echo "$WG_CONFIG"
} # ~~ function override insertion point ~~ if [[ $# -eq 1 && ( $1 == --help || $1 == -h || $1 == help ) ]]; then
cmd_usage
elif [[ $# -eq 2 && $1 == up ]]; then
auto_su
detect_launchd
parse_options "$2"
cmd_up
elif [[ $# -eq 2 && $1 == down ]]; then
auto_su
parse_options "$2"
cmd_down
elif [[ $# -eq 2 && $1 == save ]]; then
auto_su
parse_options "$2"
cmd_save
elif [[ $# -eq 2 && $1 == strip ]]; then
auto_su
parse_options "$2"
cmd_strip
else
cmd_usage
exit 1
fi [[ -n $LAUNCHED_BY_LAUNCHD ]] && wait exit 0

解决 wg-quick 在 Mac 上 bash 3 无法运行的问题的更多相关文章

  1. 尝试在mac上用dotnet cli运行asp.net core示例程序

    自从知道微软用dotnet cli取代dnx之后,一直在等dotnet cli支持asp.net core... 昨天看到这篇新闻(ASP.NET Core 1.0 Hello World)后,才知道 ...

  2. 完美解决 .txt文件在Mac上不能打开的问题

  3. Mac上使用selenium自动运行chrome

    一.用我们的老朋友pip把selenium装好 pip install selenium 二.用webdriver.Chrome启动Chrome浏览器 from selenium import web ...

  4. mac上SVN项目管理,提示被锁定的解决方法

    问题 mac上SVN项目管理,提示被锁定.不能commit.也不能update.提示 clean the working copy and then. .. 解决方法 watermark/2/text ...

  5. 新手使用mac上的textedit写HTML时遇到的问题及解决办法

    刚开始在mac上学习HTML,总结一下遇到的问题和解决办法 问题:使用textedit编写html,在网页上却仍然显示的是代码. 解决办法: 打开textedit后打开文本编辑 选择偏好设置 按如图所 ...

  6. mac 上运行cassandra出现的java.net.MalformedURLException: Local host name unknown: java.net.UnknownHostException: : : unknown error错误解决方法

    mac 上运行cassandra出现的java.net.MalformedURLException: Local host name unknown: java.net.UnknownHostExce ...

  7. Mac上安装第三方应用显示包资源破坏解决办法

    Mac上安装第三方应用显示包资源破坏解决办法 步骤1:Spotlight搜索(快捷键:command+空格或右上角搜索的符号):搜索 “终端”步骤2:直接复制粘贴 sudo spctl --maste ...

  8. 大型网站技术架构(四)--核心架构要素 开启mac上印象笔记的代码块 大型网站技术架构(三)--架构模式 JDK8 stream toMap() java.lang.IllegalStateException: Duplicate key异常解决(key重复)

    大型网站技术架构(四)--核心架构要素   作者:13GitHub:https://github.com/ZHENFENG13版权声明:本文为原创文章,未经允许不得转载.此篇已收录至<大型网站技 ...

  9. Mac 不显示未知来源选项的解决办法/连接不上网络

    原文来自百度经验: http://jingyan.baidu.com/article/eae078278b37d41fec5485b2.html 灰常感谢原作 关于mac无法连接wifi,我的解决办法 ...

  10. Mac上解决Chrome浏览器跨域问题

    最近做前端开发总是遇到一个很奇怪的现象,同一个AJAX请求,在Chrome里调试的时候就会提示跨域,但是在手机模拟器或者真机上调试的时候就不会,于是百度了一下,发现是Chrome的安全策略导致的,需要 ...

随机推荐

  1. 使用ptrace将标准输出重定位到文件

    首先使用PTRACE_SYSCALL获取到系统调用号,如果是write则将文件描述符从标准输出变为我们打开的文件 #include <stdio.h> #include <fcntl ...

  2. 如何制作 Storybook Day 网页上的 3D 效果?

    Storybook 刚刚达到了一个重要的里程牌:7.0 版本!为了庆祝,该团队举办了他们的第一次用户大会 - Storybook Day.为了更特别,在活动页面中添加了一个视觉上令人惊叹的 3D 插图 ...

  3. 前端仿今日头条、网易新闻 tabs组件,根据文字多少自适应tab项宽度,支持自定义标题栏

    快速实现 前端仿今日头条网易新闻 tabs 组件标签页,根据文字多少自适应 tab项宽度, 详情请访问uni-app插件市场地址:https://ext.dcloud.net.cn/plugin?id ...

  4. .Net全网最简Redis操作

    支持.Net/.Net Core/.Net Framework,可以部署在Docker, Windows, Linux, Mac. Redis作为一款主流的缓存工具在业内已广受欢迎.本文将会介绍操作R ...

  5. 高可用只读,让RDS for MySQL更稳定

    摘要:业务应用对数据库的数据请求分写请求(增删改)和读请求(查).当存在大量读请求时,为避免读请求阻塞写请求,数据库会提供只读实例方案.通过主实例+N只读实例的方式,实现读写分离,满足大量的数据库读取 ...

  6. 烧死10亿脑细胞的SQL长啥样?

    1 前言 今天在生产中碰到了一个让我十分费解的 SQL,十分有趣. 2 现象 SQL 很好复现,就是逻辑看起来有点唬人 postgres=# create table test(id1 int,id2 ...

  7. shell: xscp

    #!/bin/bash ips=( 1.1.1.1 1.1.1.2 ) user= passwd= for i in ${ips[@]} do echo "== $i ==" ss ...

  8. javascript中的垃圾回收机制的一些知识记录

    调用栈中的数据是如何回收的 原始类型的数据会分配到栈中 引用类型的数据会被分配到堆中 在执行代码的过程中,如果遇到了一个函数,js引擎会创建该函数的执行上下文,并将该函数的上下文压入调用栈中,与此同时 ...

  9. ubuntu 安装sublime

    Install the GPG key: wget -qO - https://download.sublimetext.com/sublimehq-pub.gpg | sudo apt-key ad ...

  10. 基于AIidlux平台的自动驾驶环境感知与智能预警

    自动驾驶汽车又称为无人驾驶车,是一种需要驾驶员辅助或者完全不需操控的车辆. 自动驾驶分级: 自动驾驶系统的组成部分: 环境感知系统: 自动驾驶系统架构: 自动驾驶数据集: Aidlux的作用: YOL ...