feat: add nosudo

This commit is contained in:
2026-06-25 10:46:07 +08:00
parent 0e7fe55474
commit e8aae9738b
9 changed files with 358 additions and 55 deletions
+31
View File
@@ -0,0 +1,31 @@
#!/usr/bin/env bash
# Copy stdin to the system clipboard (macOS / Linux X11 / Linux Wayland).
set -euo pipefail
if command -v pbcopy >/dev/null 2>&1; then
pbcopy
elif [ "${XDG_SESSION_TYPE:-}" = wayland ] || [ -n "${WAYLAND_DISPLAY:-}" ]; then
if command -v wl-copy >/dev/null 2>&1; then
wl-copy --no-newline
else
echo "clip-copy: wl-copy not found (Wayland session)" >&2
exit 1
fi
elif [ -n "${DISPLAY:-}" ]; then
if command -v xclip >/dev/null 2>&1; then
xclip -selection clipboard
elif command -v xsel >/dev/null 2>&1; then
xsel --clipboard --input
else
echo "clip-copy: xclip or xsel not found (DISPLAY=$DISPLAY)" >&2
exit 1
fi
elif command -v xclip >/dev/null 2>&1; then
xclip -selection clipboard
elif command -v xsel >/dev/null 2>&1; then
xsel --clipboard --input
else
echo "clip-copy: no clipboard tool (pbcopy / wl-copy / xclip / xsel)" >&2
exit 1
fi
+76
View File
@@ -0,0 +1,76 @@
#!/bin/bash
# 用法:
# ./dns-clean.sh # 清理 macOS / Linux 系统 DNS 缓存
set -e
SUDO=""
[ "$(id -u)" -ne 0 ] && SUDO="sudo"
flush_macos() {
echo "macOS: 清理 DNS 缓存..."
$SUDO dscacheutil -flushcache
$SUDO killall -HUP mDNSResponder 2>/dev/null || true
$SUDO killall mDNSResponderHelper 2>/dev/null || true
echo "macOS DNS 缓存已清理"
}
flush_linux() {
local flushed=0
echo "Linux: 清理 DNS 缓存..."
if command -v resolvectl &>/dev/null; then
if $SUDO resolvectl flush-caches 2>/dev/null; then
echo " - systemd-resolved (resolvectl) 缓存已清理"
flushed=1
fi
elif command -v systemd-resolve &>/dev/null; then
if $SUDO systemd-resolve --flush-caches 2>/dev/null; then
echo " - systemd-resolved (systemd-resolve) 缓存已清理"
flushed=1
fi
fi
if command -v systemctl &>/dev/null; then
if systemctl is-active --quiet nscd 2>/dev/null; then
$SUDO systemctl restart nscd
echo " - nscd 已重启"
flushed=1
fi
if systemctl is-active --quiet dnsmasq 2>/dev/null; then
$SUDO systemctl restart dnsmasq
echo " - dnsmasq 已重启"
flushed=1
fi
if systemctl is-active --quiet unbound 2>/dev/null; then
if command -v rndc &>/dev/null; then
$SUDO rndc flush 2>/dev/null && echo " - unbound 缓存已清理" && flushed=1
else
$SUDO systemctl restart unbound
echo " - unbound 已重启"
flushed=1
fi
fi
fi
if [ "$flushed" -eq 0 ]; then
echo "未检测到常见 DNS 缓存服务 (systemd-resolved / nscd / dnsmasq / unbound)"
echo "若仍有问题,可尝试重启 NetworkManager 或检查本地 DNS 配置"
exit 1
fi
echo "Linux DNS 缓存已清理"
}
case "$(uname -s)" in
Darwin) flush_macos ;;
Linux) flush_linux ;;
*)
echo "错误: 不支持的操作系统: $(uname -s)"
exit 1
;;
esac
+51
View File
@@ -0,0 +1,51 @@
#!/bin/bash
# 将用户加入 docker 组(免 sudo 使用 docker)
# 用法: sudo docker-group <user>
# 示例: sudo docker-group xuser
set -euo pipefail
usage() {
cat <<'EOF'
用法: sudo docker-group <user>
将 <user> 加入 docker 组,之后可直接运行 docker(无需 sudo)。
示例:
sudo docker-group xuser
说明:
- 用户需重新登录或 newgrp docker 后生效
- 安装 Docker 时 docker-install.sh 只会把当时的 $USER 加入组
EOF
exit 1
}
[[ "${1:-}" == "-h" || "${1:-}" == "--help" ]] && usage
[[ $# -eq 1 ]] || usage
if [[ $EUID -ne 0 ]]; then
echo "错误: 请使用 sudo 运行,例如: sudo $0 $1"
exit 1
fi
user="$1"
if ! id "$user" &>/dev/null; then
echo "错误: 用户不存在: $user"
exit 1
fi
if ! getent group docker &>/dev/null; then
echo "错误: docker 组不存在,请先安装 Docker(例如运行 docker-install.sh)"
exit 1
fi
if id -nG "$user" | tr ' ' '\n' | grep -qx docker; then
echo "用户 $user 已在 docker 组中"
exit 0
fi
usermod -aG docker "$user"
echo "已将 $user 加入 docker 组"
echo "请让用户重新登录,或执行: su - $user -c 'newgrp docker'"
+97
View File
@@ -0,0 +1,97 @@
#!/bin/bash
# 为指定用户配置某命令的免密 sudo(写入 /etc/sudoers.d/)
# 用法: sudo nosudo <user> <command>
# 示例: sudo nosudo xuser docker
set -euo pipefail
usage() {
cat <<'EOF'
用法: sudo nosudo <user> <command>
为 <user> 配置对 <command> 的免密 sudo(NOPASSWD)。
示例:
sudo nosudo xuser docker
sudo nosudo xuser /usr/bin/systemctl
说明:
- 每个命令单独一个文件(nosudo-<user>-<命令名>),可多次执行、互不覆盖
例如 nosudo xuser kubectl 与 nosudo xuser helm 会各写一条规则,同时生效
- 仅允许免密执行解析到的那个可执行文件路径(含子命令参数仍受 sudo 规则约束)
- 对 docker,更推荐: sudo docker-group <user>(无需 sudo 即可用 docker)
- 删除规则: sudo rm /etc/sudoers.d/nosudo-<user>-<name>
EOF
exit 1
}
[[ "${1:-}" == "-h" || "${1:-}" == "--help" ]] && usage
[[ $# -eq 2 ]] || usage
if [[ $EUID -ne 0 ]]; then
echo "错误: 请使用 sudo 运行,例如: sudo $0 $*"
exit 1
fi
if [[ ! -d /etc/sudoers.d ]]; then
echo "错误: 未找到 /etc/sudoers.d(当前系统可能不支持此方式)"
exit 1
fi
user="$1"
cmd="$2"
if ! id "$user" &>/dev/null; then
echo "错误: 用户不存在: $user"
exit 1
fi
if [[ "$cmd" == /* ]]; then
cmd_path="$cmd"
else
cmd_path="$(command -v "$cmd" 2>/dev/null || true)"
fi
if [[ -z "$cmd_path" || ! -x "$cmd_path" ]]; then
echo "错误: 找不到可执行文件: $cmd"
echo "提示: 可先安装该命令,或传入绝对路径,例如 /usr/bin/docker"
exit 1
fi
name="$(basename "$cmd_path")"
file="/etc/sudoers.d/nosudo-${user}-${name}"
if [[ -f "$file" ]]; then
if grep -qF "NOPASSWD: ${cmd_path}" "$file" 2>/dev/null; then
echo "已存在相同规则: $file"
exit 0
fi
fi
tmp="$(mktemp)"
trap 'rm -f "$tmp"' EXIT
cat >"$tmp" <<EOF
# Managed by nosudo ($0)
# user=$user command=$cmd_path
${user} ALL=(ALL) NOPASSWD: ${cmd_path}
EOF
if ! visudo -cf "$tmp" >/dev/null; then
echo "错误: sudoers 语法校验失败"
visudo -cf "$tmp" || true
exit 1
fi
install -m 0440 -o root -g root "$tmp" "$file"
echo "已写入: $file"
echo "内容: ${user} ALL=(ALL) NOPASSWD: ${cmd_path}"
echo ""
echo "验证(切换到该用户后):"
echo " sudo -u ${user} sudo -n ${cmd_path} version 2>/dev/null || sudo -u ${user} sudo -n ${cmd_path} --help | head -1"
if [[ "$name" == "docker" ]]; then
echo ""
echo "提示: 若希望直接运行 docker(不用 sudo),请执行:"
echo " sudo docker-group ${user}"
fi
+29 -3
View File
@@ -2,14 +2,40 @@
# 用法:
# ./scan-ip.sh # ICMP 扫描本网段在线 IP
# ./scan-ip.sh 10.0.0 # ICMP 扫描指定网段(10.0.0.1-254)
# ./scan-ip.sh 22 # 扫描本网段中 22 端口开放的 IP
# ./scan-ip.sh 80,443,8080 # 扫描本网段中任一指定端口开放的 IP
# ./scan-ip.sh 22 10.0.0 # 指定网段前缀(不写则使用本机所在网段)
# ./scan-ip.sh 22 10.0.0 # 指定网段前缀 + 端口(顺序不限)
# ./scan-ip.sh 10.0.0 22 # 同上
PORT_SPEC="$1"
PREFIX_ARG="$2"
TIMEOUT=1
is_port_spec() {
[[ "$1" =~ ^[0-9]+$ || "$1" =~ ^[0-9]+-[0-9]+$ || "$1" =~ ^[0-9,]+$ ]]
}
is_ip_prefix() {
[[ "$1" =~ ^[0-9]{1,3}(\.[0-9]{1,3}){1,3}$ ]]
}
PORT_SPEC=""
PREFIX_ARG=""
if [ -n "$1" ] && is_ip_prefix "$1"; then
PREFIX_ARG="$1"
[ -n "$2" ] && is_port_spec "$2" && PORT_SPEC="$2"
elif [ -n "$1" ]; then
is_port_spec "$1" && PORT_SPEC="$1"
[ -n "$2" ] && is_ip_prefix "$2" && PREFIX_ARG="$2"
fi
if [ -n "$1" ] && [ -z "$PORT_SPEC" ] && [ -z "$PREFIX_ARG" ]; then
echo "错误: 无法识别参数: $1"
echo "端口支持: 单端口(22) / 列表(80,443) / 范围(8000-8100)"
echo "网段支持: 前缀(10.0.0 或 192.168.1.0)"
exit 1
fi
if command -v ip &>/dev/null; then
LOCAL_IP=$(ip addr show | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}' | cut -d/ -f1 | head -n 1)
elif command -v ifconfig &>/dev/null; then