问题原因

我可以理解,开发人员不想使用苹果使用的旧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. 更换Mysql数据库-----基于Abo.io 的书籍管理Web应用程序

    之前公司一直使用的是ASP.NET Boilerplate (ABP),但是当解决方案变得很大时,项目启动就变得非常慢,虽然也想了一些办法,将一些基础模块做成Nuget包的形式,让整个解决方案去引用. ...

  2. 面向生信分析的高性 RStudio 服务器

    因需要超大内存的拼接/比对/表达量计算发愁? 为了使用组里的服务器而被困在实验室? 浪费大量的时间龟速下载 NCBI 的数据? 快来看看云筏 HPC 吧! https://my.cloudraft.c ...

  3. std::aligned_alloc

    定义于头文件 <cstdlib> (c++) void * aligned_alloc ( std::size_t alignment, std::size_t size); (c++17 ...

  4. 【HarmonyOS】如何获取公共目录的图片等文件(API7 FA模型JS语言)

    ​ [关键字] API7.JS.公共目录.@ohos.multimedia.mediaLibrary [前言] 在使用API7 JS开发HarmonyOS应用时,需要获取非应用目录即内部存储公共目录下 ...

  5. Javaweb文件上传至服务器/从服务器下载

    Javaweb文件上传至服务器/从服务器下载 思路图 文件上传思路: 也可以直接看代码 判断是不是文件表单(判断form的enctype是不是="multipart/form-data&qu ...

  6. Git的基本操作(CUDR)及分支

    ## 安装 到Git官网下载,网站地址:https://git-scm.com/downloads 需要从网上下载一个,然后进行默认安装即可.安装完成后,在开始菜单里面找到 "Git --& ...

  7. centOS7 磁盘扩容(2T以上)

    centOS7 磁盘扩容 1.安装parted分区工具 yum install -y parted 2.查看服务器分区情况 #fdisk -l 或者 lsblk 找到新增磁盘名称 例如/dev/sdb ...

  8. MyBatis(RowBounds)分页了解内容

    RowBounds 不在使用SQL实现分页 1.接口 List<User> getUserByRowBounds(); 2.mapper.xml <select id="g ...

  9. UE4构建基础和实践:一、概述

    序言 构建这个概念是和应用程序包及资源等相关的,它的特点是使用脚本控制一系列的任务的处理,以减少人力操作带来的成本和操作失误风险. 在UE的概念里,构建往往是和打包相关的(如编译.cook.压缩打包等 ...

  10. asp.net core之Startup

    Startup介绍 Startup是Asp.net Core的应用启动入口.在.NET5及之前一般会使用startup.cs类进行程序初始化构造.如下: public class Startup { ...