feat: add nosudo
This commit is contained in:
+53
-51
@@ -20,7 +20,7 @@
|
||||
"vim.normalModeKeyBindingsNonRecursive": [
|
||||
{
|
||||
"before": ["<space>"],
|
||||
"commands": ["vspacecode.space"],
|
||||
"commands": ["vspacecode.space"]
|
||||
},
|
||||
{
|
||||
"before": [","],
|
||||
@@ -28,15 +28,15 @@
|
||||
"vspacecode.space",
|
||||
{
|
||||
"command": "whichkey.triggerKey",
|
||||
"args": "m",
|
||||
},
|
||||
],
|
||||
},
|
||||
"args": "m"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"vim.visualModeKeyBindingsNonRecursive": [
|
||||
{
|
||||
"before": ["<space>"],
|
||||
"commands": ["vspacecode.space"],
|
||||
"commands": ["vspacecode.space"]
|
||||
},
|
||||
{
|
||||
"before": [","],
|
||||
@@ -44,18 +44,18 @@
|
||||
"vspacecode.space",
|
||||
{
|
||||
"command": "whichkey.triggerKey",
|
||||
"args": "m",
|
||||
},
|
||||
],
|
||||
"args": "m"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"before": [">"],
|
||||
"commands": ["editor.action.indentLines"],
|
||||
"commands": ["editor.action.indentLines"]
|
||||
},
|
||||
{
|
||||
"before": ["<"],
|
||||
"commands": ["editor.action.outdentLines"],
|
||||
},
|
||||
"commands": ["editor.action.outdentLines"]
|
||||
}
|
||||
],
|
||||
"workbench.panel.location": "right",
|
||||
"gitHistory.hideCommitViewExplorer": true,
|
||||
@@ -67,16 +67,16 @@
|
||||
"sync.gist": "3c4e02a02a0d110622006b8c8b058fa5",
|
||||
"go.languageServerFlags": ["-rpc.trace"],
|
||||
"[json]": {
|
||||
"editor.defaultFormatter": "vscode.json-language-features",
|
||||
"editor.defaultFormatter": "vscode.json-language-features"
|
||||
},
|
||||
"files.associations": {
|
||||
"*.html": "html",
|
||||
"*.json": "jsonc",
|
||||
"NOTES.txt": "helm",
|
||||
"Dockerfile": "dockerfile",
|
||||
"Dockerfile": "dockerfile"
|
||||
},
|
||||
"[helm]": {
|
||||
"editor.defaultFormatter": "redhat.vscode-yaml",
|
||||
"editor.defaultFormatter": "redhat.vscode-yaml"
|
||||
// "editor.formatOnSave": false // alternatively, force it to leave you alone
|
||||
},
|
||||
"gitlens.codeLens.recentChange.enabled": false,
|
||||
@@ -87,19 +87,19 @@
|
||||
// "terminal.integrated.shell.osx": "/bin/zsh",
|
||||
"editor.fontFamily": "Fira Code, Sarasa Fixed SC Nerd Font, Menlo, Monaco, 'Courier New', monospace",
|
||||
"[javascript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"search.followSymlinks": false,
|
||||
"go.autocompleteUnimportedPackages": true,
|
||||
"[jsonc]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"vscode-neovim.mouseSelectionStartVisualMode": true,
|
||||
"go.lintTool": "golangci-lint",
|
||||
"go.lintFlags": ["--config=~/.dotfile/golang/golangci.yml"],
|
||||
"go.liveErrors": {
|
||||
"enabled": false,
|
||||
"delay": 500,
|
||||
"delay": 500
|
||||
},
|
||||
"python.languageServer": "Pylance",
|
||||
"go.overwriteGoplsMiddleware": {},
|
||||
@@ -107,20 +107,20 @@
|
||||
"[go]": {
|
||||
"editor.formatOnSave": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports": "explicit",
|
||||
"source.organizeImports": "explicit"
|
||||
},
|
||||
"editor.snippetSuggestions": "none",
|
||||
"editor.defaultFormatter": "golang.go",
|
||||
"editor.defaultFormatter": "golang.go"
|
||||
},
|
||||
"[go.mod]": {
|
||||
"editor.formatOnSave": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports": "explicit",
|
||||
},
|
||||
"source.organizeImports": "explicit"
|
||||
}
|
||||
},
|
||||
"gopls": {
|
||||
"usePlaceholders": true,
|
||||
"staticcheck": false,
|
||||
"staticcheck": false
|
||||
},
|
||||
"go.testFlags": ["-v"],
|
||||
"vscode-neovim.neovimExecutablePaths.darwin": "/usr/local/bin/nvim",
|
||||
@@ -136,22 +136,22 @@
|
||||
"security.workspace.trust.untrustedFiles": "open",
|
||||
"workbench.tree.indent": 4,
|
||||
"[html]": {
|
||||
"editor.defaultFormatter": "vscode.html-language-features",
|
||||
"editor.defaultFormatter": "vscode.html-language-features"
|
||||
},
|
||||
"python.defaultInterpreterPath": "/usr/local/bin/python3",
|
||||
"[python]": {
|
||||
"editor.formatOnType": true,
|
||||
"editor.defaultFormatter": "ms-python.python",
|
||||
"editor.defaultFormatter": "ms-python.python"
|
||||
},
|
||||
"[go][go.mod]": {
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports": "explicit",
|
||||
},
|
||||
"source.organizeImports": "explicit"
|
||||
}
|
||||
},
|
||||
"update.showReleaseNotes": false,
|
||||
"terminal.integrated.defaultProfile.osx": "fish",
|
||||
"extensions.experimental.affinity": {
|
||||
"asvetliakov.vscode-neovim": 1,
|
||||
"asvetliakov.vscode-neovim": 1
|
||||
},
|
||||
"makefile.configureOnOpen": false,
|
||||
"python.terminal.activateEnvInCurrentTerminal": true,
|
||||
@@ -159,10 +159,12 @@
|
||||
"remote.SSH.defaultForwardedPorts": [],
|
||||
"remote.SSH.useLocalServer": false,
|
||||
"remote.SSH.connectTimeout": 30,
|
||||
"remote.SSH.localServerDownload": "always",
|
||||
"remote.SSH.remotePlatform": {
|
||||
"box1": "linux",
|
||||
"hx80": "linux",
|
||||
"hx20": "linux",
|
||||
"pc30": "linux"
|
||||
},
|
||||
"editor.formatOnSave": true,
|
||||
"pylint.enabled": false,
|
||||
@@ -170,50 +172,50 @@
|
||||
"python.analysis.packageIndexDepths": [
|
||||
{
|
||||
"name": "sklearn",
|
||||
"depth": 2,
|
||||
"depth": 2
|
||||
},
|
||||
{
|
||||
"name": "matplotlib",
|
||||
"depth": 2,
|
||||
"depth": 2
|
||||
},
|
||||
{
|
||||
"name": "scipy",
|
||||
"depth": 2,
|
||||
"depth": 2
|
||||
},
|
||||
{
|
||||
"name": "django",
|
||||
"depth": 2,
|
||||
"depth": 2
|
||||
},
|
||||
{
|
||||
"name": "flask",
|
||||
"depth": 2,
|
||||
"depth": 2
|
||||
},
|
||||
{
|
||||
"name": "fastapi",
|
||||
"depth": 2,
|
||||
},
|
||||
"depth": 2
|
||||
}
|
||||
],
|
||||
"[shellscript]": {
|
||||
"editor.defaultFormatter": "foxundermoon.shell-format",
|
||||
"editor.defaultFormatter": "foxundermoon.shell-format"
|
||||
},
|
||||
// "[dockerfile]": {
|
||||
// "editor.defaultFormatter": "foxundermoon.shell-format"
|
||||
// },
|
||||
"[ignore]": {
|
||||
"editor.defaultFormatter": "foxundermoon.shell-format",
|
||||
"editor.defaultFormatter": "foxundermoon.shell-format"
|
||||
},
|
||||
"[properties]": {
|
||||
"editor.defaultFormatter": "foxundermoon.shell-format",
|
||||
"editor.defaultFormatter": "foxundermoon.shell-format"
|
||||
},
|
||||
"editor.codeActionsOnSave": {
|
||||
// "source.organizeImports": "explicit",
|
||||
"source.fixAll.eslint": "explicit",
|
||||
"source.fixAll.eslint": "explicit"
|
||||
},
|
||||
"[proto3]": {
|
||||
"editor.defaultFormatter": "zxh404.vscode-proto3",
|
||||
"editor.defaultFormatter": "zxh404.vscode-proto3"
|
||||
},
|
||||
"[dotenv]": {
|
||||
"editor.defaultFormatter": "foxundermoon.shell-format",
|
||||
"editor.defaultFormatter": "foxundermoon.shell-format"
|
||||
},
|
||||
"typescript.preferences.quoteStyle": "single",
|
||||
"javascript.preferences.quoteStyle": "single",
|
||||
@@ -221,7 +223,7 @@
|
||||
"pretty-formatter.quoteConvert": "single",
|
||||
"html.completion.attributeDefaultValue": "singlequotes",
|
||||
"[typescriptreact]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"prettier.jsxSingleQuote": true,
|
||||
"go.buildFlags": ["-tags=wireinject"],
|
||||
@@ -231,7 +233,7 @@
|
||||
"editor.tabSize": 2,
|
||||
"editor.autoIndent": "advanced",
|
||||
"diffEditor.ignoreTrimWhitespace": false,
|
||||
"editor.defaultColorDecorators": "never",
|
||||
"editor.defaultColorDecorators": "never"
|
||||
},
|
||||
"html.format.unformatted": "",
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
@@ -243,34 +245,33 @@
|
||||
"name": "Space (Global Leader)",
|
||||
"type": "bind",
|
||||
"command": "vspacecode.space",
|
||||
"when": "editorTextFocus || explorerViewletVisible || terminalFocus",
|
||||
"when": "editorTextFocus || explorerViewletVisible || terminalFocus"
|
||||
},
|
||||
{
|
||||
"keys": "w.t",
|
||||
"name": "Toggle Terminal",
|
||||
"type": "command",
|
||||
"command": "workbench.action.terminal.toggleTerminal",
|
||||
"command": "workbench.action.terminal.toggleTerminal"
|
||||
},
|
||||
{
|
||||
"keys": "w.w",
|
||||
"name": "Toggle AI Sidebar",
|
||||
"type": "command",
|
||||
"command": "workbench.action.toggleAuxiliaryBar",
|
||||
"command": "workbench.action.toggleAuxiliaryBar"
|
||||
},
|
||||
{
|
||||
"keys": "w.e",
|
||||
"name": "Focus First Editor Group",
|
||||
"type": "command",
|
||||
"command": "workbench.action.focusFirstEditorGroup",
|
||||
},
|
||||
"command": "workbench.action.focusFirstEditorGroup"
|
||||
}
|
||||
],
|
||||
"[java]": {
|
||||
"editor.suggest.snippetsPreventQuickSuggestions": false,
|
||||
"editor.suggest.snippetsPreventQuickSuggestions": false
|
||||
},
|
||||
"git.confirmSync": false,
|
||||
"editor.dropIntoEditor.preferences": [],
|
||||
"whichkey.bindingOverrides": [],
|
||||
"remote.SSH.localServerDownload": "always",
|
||||
"workbench.colorCustomizations": {},
|
||||
"javascript.format.enable": false,
|
||||
"typescript.format.enable": false,
|
||||
@@ -282,8 +283,9 @@
|
||||
"ANTHROPIC_DEFAULT_SONNET_MODEL": "MiniMax-M2.1",
|
||||
"ANTHROPIC_MODEL": "MiniMax-M2.1",
|
||||
"API_TIMEOUT_MS": "3000000",
|
||||
"CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": 1,
|
||||
"CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": 1
|
||||
},
|
||||
"claudeCode.preferredLocation": "panel",
|
||||
"window.autoDetectColorScheme": false,
|
||||
"vim.disableExtension": true
|
||||
}
|
||||
|
||||
+1
-1
@@ -103,7 +103,7 @@ end
|
||||
#################################################################
|
||||
# git
|
||||
# alias
|
||||
alias gitb="git branch --show-current | tr -d '\n' | pbcopy"
|
||||
alias gitb="git branch --show-current | tr -d '\n' | clip-copy.sh"
|
||||
alias gci="golangci-lint run -c=~/.dotfile/golang/golangci.yml ./..."
|
||||
alias gmt="go mod tidy"
|
||||
alias gtc="go test -gcflags=all=-l -cover ./..."
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
function pwdc --description 'Copy current directory path to clipboard'
|
||||
set -l dir (pwd -P)
|
||||
if not printf '%s' $dir | clip-copy.sh
|
||||
return 1
|
||||
end
|
||||
echo "Copied: "(string replace $HOME '~' $dir)
|
||||
end
|
||||
Executable
+31
@@ -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
|
||||
Executable
+76
@@ -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
|
||||
Executable
+51
@@ -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'"
|
||||
Executable
+97
@@ -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
@@ -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
|
||||
|
||||
+13
@@ -14,5 +14,18 @@ else
|
||||
echo "[zsh] Oh My Zsh 未安装,请运行: bash ~/.dotfile/script/zsh-init.sh" >&2
|
||||
fi
|
||||
|
||||
# 复制当前 git 分支名到剪贴板(macOS / Linux)
|
||||
gitb() {
|
||||
git branch --show-current | tr -d '\n' | clip-copy.sh
|
||||
}
|
||||
|
||||
# 复制当前目录到剪贴板(macOS / Linux)
|
||||
pwdc() {
|
||||
local dir
|
||||
dir="$(pwd -P)"
|
||||
printf '%s' "$dir" | clip-copy.sh || return 1
|
||||
echo "Copied: ${dir/#$HOME/~}"
|
||||
}
|
||||
|
||||
# 本机私有配置(不纳入 dotfile)
|
||||
[[ -f "$HOME/.zshrc.local" ]] && source "$HOME/.zshrc.local"
|
||||
|
||||
Reference in New Issue
Block a user