Showing Posts From
Shell
cp 报错 cannot overwrite non-directory:目录被同名文件占位
某次要把 pojie/ 目录复制进 wpa-dictionary/ 里,cp 一直报错: $ cp -r pojie/ wpa-dictionary/pojie cp: cannot overwrite non-directory 'wpa-dictionary/pojie' with directory 'pojie/'$ cp -r pojie wpa-dictionary/ cp: cannot overwrite non-directory 'wpa-dictionary/pojie' with directory 'pojie'$ cp -f pojie wpa-dictionary/ cp: -r not specified; omitting directory 'pojie'问题原因 这个报错不是 cp 参数写错了,而是 目标路径 wpa-dictionary/pojie 已经存在一个普通文件,cp 不允许用目录去覆盖一个非目录。 先用 ls -l 确认: $ ls -l wpa-dictionary/pojie -rw-r--r-- 1 root root 1234 Jun 15 10:00 wpa-dictionary/pojie看到开头是 - 说明它是普通文件。而你想执行的 cp -r pojie wpa-dictionary/ 实际上等于 cp -r pojie wpa-dictionary/pojie——目标名字已经被文件占了。 三种处理方式 方案一:删除同名文件 如果目标位置那个文件本来就没用,直接删掉再复制: rm -f wpa-dictionary/pojie cp -r pojie wpa-dictionary/方案二:换个目标名 不想删旧文件的话,改个新名字: cp -r pojie wpa-dictionary/pojie_new方案三:先看清目录结构 用 tree 看一眼当前目录状态,避免以后再踩: tree -L 2 .或者两条 ls -ld 直接对比属性: ls -ld pojie ls -ld wpa-dictionary/pojie看到一个是 d 开头(目录)、一个是 - 开头(文件),就知道冲突在哪里了。 一句话总结 cp: cannot overwrite non-directory = 目标位置已被同名普通文件占位。要么删掉旧文件,要么换个目标名。
写个 Bash 自动 git pull:三种姿势和 cron 里的坑
服务器上想自动拉最新代码,写个脚本挂 cron 跑。看着就两行,实际上有几个必吃的坑。 最基础写法 #!/bin/bash cd /www/wwwroot/yourproject || exit 1 git pull|| exit 1:cd 失败就退出,不然当前目录是家目录,git pull 会执行在错误的仓库 保存为 pull.sh chmod +x pull.sh 执行 ./pull.sh更稳的写法:不依赖 cd git -C 可以直接指定仓库路径,省掉 cd 的失败风险: #!/bin/bash git -C /www/wwwroot/yourproject pull origin main同一个脚本要处理多个仓库时特别顺手。 挂 cron 时会踩的坑 */5 * * * * /www/wwwroot/scripts/pull.sh >> /var/log/pull.log 2>&1看着没问题,实际经常挂。原因: 1. SSH 密钥没加载 用户手动跑时有 ssh-agent。cron 里没有,git@github.com 直接拒绝。解法:走 HTTPS + PAT,别用 SSH 或在脚本里显式指定密钥:export GIT_SSH_COMMAND="ssh -i /root/.ssh/deploy_key -o StrictHostKeyChecking=no" git -C /www/wwwroot/yourproject pull origin main2. PATH 太窄 cron 的 PATH 只有 /usr/bin:/bin,找不到自定义安装的 git。crontab 里手动补: PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin */5 * * * * /www/wwwroot/scripts/pull.sh3. 分支不明确 裸 git pull 会走当前分支和默认 remote,可能拉到不该拉的分支。永远显式: git -C "$REPO" pull origin main处理本地修改的完整版 生产脚本上还得防几件事: #!/bin/bash set -eREPO=/www/wwwroot/yourproject BRANCH=maincd "$REPO"# 1. 如果本地有修改,暂存(避免 pull 失败) if [[ -n $(git status --porcelain) ]]; then echo "[$(date)] 本地有修改,先 stash" git stash push -m "auto-stash $(date +%s)" fi# 2. 拉最新 git fetch origin "$BRANCH" git reset --hard "origin/$BRANCH" # 直接对齐远程,别 merge# 3. 清空 stash(不还原,防止和拉下来的冲突) git stash clear注意 git reset --hard 会覆盖本地任何修改。这是刻意的——线上机器上不该有手改,任何修改都视为"意外"直接抹掉。要保守就用 git pull --ff-only。 大小写敏感的坑 服务器 Linux 大小写敏感,Windows / macOS 默认不敏感。仓库里同时存在: RiderAuditController.php RiderauditController.phpLinux 上拉下来会真的多出两个文件,Windows 上只能存一个,pull 立刻挂。 解法:清理仓库中的重名文件,用 git rm 保留一个: git rm --cached RiderauditController.php git commit -m "fix: 大小写重复" git push或者临时关掉大小写敏感(治标): git config core.ignorecase true一句话总结 git -C REPO pull origin BRANCH 是最省事的一行。挂 cron 要额外交代 PATH、SSH 密钥、分支名,生产脚本再套一层 reset --hard 防脏树。
Windows 杀进程:按 PID / 按名字 / 按端口
Windows 上要杀个后台跑的进程,图形界面点半天不如命令行一条搞定。 按 PID 杀(最常用) CMD taskkill /PID 1234 /F1234 换成你的 PID /F 强制结束,不加有时杀不掉PowerShell Stop-Process -Id 1234 -Force不知道 PID 怎么办 按名字找 tasklist | findstr nginx按端口找(比如 8080 被占了) netstat -ano | findstr :8080最后一列就是 PID。也可以直接: Get-NetTCPConnection -LocalPort 8080 | Select-Object OwningProcess按进程名批量杀 嫌一个个找 PID 麻烦: taskkill /IM nginx.exe /F或者 PowerShell 通配: Stop-Process -Name "nginx" -Force杀不掉的情况 碰到 拒绝访问 / Access is denied,先看是不是这几种:权限不够——右键 CMD/PowerShell "以管理员身份运行" SYSTEM 保护进程——比如 System、Registry 是杀不掉的,动它系统会重启 进程被驱动挂钩——某些安全软件会保护自身进程,得先从安全软件里退出进程有子进程且需要一起清理时: taskkill /PID 1234 /T /F/T = 连同子进程一起杀。 一张表速查目的 命令按 PID 杀 taskkill /PID <pid> /F按进程名杀 taskkill /IM <name>.exe /F连子进程一起杀 taskkill /PID <pid> /T /F查端口占用 netstat -ano | findstr :<port>查进程名 tasklist | findstr <name>PowerShell 版本 Stop-Process -Id <pid> -Force
PID 和端口互查:Linux 和 Windows 的常用命令
调试服务、清理端口占用、看某个进程到底连了哪儿——PID 和端口互查是日常操作。整理一份速查。 Linux:按端口找 PID 现代系统首选 ss(netstat 老了,很多发行版默认不装): ss -lntp | grep :8080输出: LISTEN 0 128 *:8080 *:* users:(("java",pid=12345,fd=45))PID 就是 12345。要看 UDP 加 -u,全协议 ss -tulnp。 lsof 也行,输出更清楚: sudo lsof -i:8080Linux:按 PID 找端口 ss -tunp | grep "pid=12345"或者: sudo lsof -Pan -p 12345 -i后者会同时列出该进程的所有连接(监听 + 已连接),排查网络问题特别顺手: COMMAND PID USER FD TYPE DEVICE NAME java 12345 root 45u IPv4 TCP *:8080 (LISTEN) java 12345 root 46u IPv4 TCP 10.0.0.5:8080->8.8.8.8:443 (ESTABLISHED)Linux:查所有监听端口 ss -lntp # TCP ss -lunp # UDP ss -tulnp # 全部Windows:按端口找 PID netstat -ano | findstr :8080输出最后一列是 PID。看进程名: tasklist | findstr 12345PowerShell 版本更直观: Get-NetTCPConnection -LocalPort 8080 | Select-Object LocalAddress, State, OwningProcess | Format-TableWindows:按 PID 找端口 netstat -ano | findstr 12345PowerShell: Get-NetTCPConnection | Where-Object OwningProcess -eq 12345Docker 里的进程 服务在容器里跑,宿主机 ss 只看到 docker-proxy。有两种方式: 宿主机上看容器映射: docker ps --format 'table {{.Names}}\t{{.Ports}}'进容器里看真实进程: docker exec -it <container> ss -lntpWindows:把占端口的进程杀掉 一条链: for /f "tokens=5" %a in ('netstat -ano ^| findstr :8080 ^| findstr LISTENING') do taskkill /PID %a /F或者 PowerShell: Get-NetTCPConnection -LocalPort 8080 | ForEach-Object { Stop-Process -Id $_.OwningProcess -Force }Linux:一条命令连查带杀 sudo fuser -k 8080/tcpfuser 会把所有占用 8080/TCP 的进程直接杀掉,慎用。 一个小坑:找不到 PID Linux 上 ss 或 lsof 有时看不到 PID: users:(("java",pid=?,fd=?))多半是没加 sudo——别的用户的进程只有 root 能看。 Windows 上 netstat -ano 看到 PID 4 的东西一般是内核网络栈(System 进程),不是你的应用。 一句话总结 Linux 用 ss -lntp + lsof,Windows 用 netstat -ano + tasklist。PowerShell 用户直接上 Get-NetTCPConnection 更顺。
macOS 上 nc -l -p 报错:BSD netcat 的参数和 Linux 不一样
Linux 上抄来的教程: nc -l -p 1337在 macOS 直接报错。因为 macOS 自带的是 BSD 版 netcat,参数和 Linux 上常见的 GNU/OpenBSD 版有几处不兼容。 正确写法 nc -l 1337或者加日志: nc -lv 1337-l:监听 -v:verbose,显示连接信息 端口号直接跟在后面,不用 -p客户端连过来: nc 127.0.0.1 1337持续监听多个连接 单次 -l 处理完一个连接就退出。想常驻用 -k(keep-open): nc -lk 1337老版本不支持 -k 的话,套一层循环: while true; do nc -l 1337; doneLinux vs macOS 差异速查目的 Linux (nmap-netcat 或 nc.openbsd) macOS BSD nc监听端口 nc -l -p 1337 nc -l 1337短参组合 nc -lp 1337 不支持 -p 监听持续监听 nc -k -l 1337 nc -lk 1337UDP 监听 nc -u -l -p 1337 nc -u -l 1337端口扫描 nc -zv host 20-30 一样指定源端口发送 nc -p 1234 host 80 一样-p 在 macOS 里只用于发送端指定源端口,监听时不能用。 检查你的 nc 是哪一版 which nc # 通常 /usr/bin/nc nc -h 2>&1 | head -3BSD 版的帮助会显示 usage: nc [-46...。GNU 版会显示 Ncat: Version 7.xx。 换成 ncat(可选) 如果不想记两套参数,直接装 nmap 自带的 ncat: brew install nmap ncat -l 1337 # 和 Linux 上写法一样 ncat -lk 1337ncat 参数在所有平台一致,还额外支持 SSL、SOCKS 代理,取代 BSD nc 很合适。 常见踩坑权限:监听 1024 以下端口需要 sudo 防火墙:macOS 系统偏好设置里的防火墙可能拦掉外部连接 AirDrop / IPv6:BSD nc -l 8080 可能只绑 IPv6(::)不绑 IPv4,测试时改用 nc -4 -l 8080 强制 v4一句话总结 macOS 的 nc 是 BSD 版,监听不用 -p:nc -l 1337 或 nc -lk 1337。要跨平台无差别用就装 ncat。
一个 bat 脚本清 Windows 的 Temp 目录
Windows 用久了 C:\Users\<你>\AppData\Local\Temp 里能塞几 GB 垃圾——浏览器缓存、安装包解压残留、Office 恢复文件。用图形界面点很慢,一个 bat 脚本清完事。 最省事版本 用系统自带的 %TEMP% 变量,不用自己拼路径: @echo off setlocalecho 当前用户: %USERNAME% echo Temp 目录: %TEMP%del /f /s /q "%TEMP%\*" >nul 2>&1 for /d %%p in ("%TEMP%\*") do rmdir /s /q "%%p" >nul 2>&1echo 清理完成 pause拆开看:del /f /s /q — 强制、递归、静默删除文件 for /d ... rmdir /s /q — 遍历所有子目录并递归删除 >nul 2>&1 — 屏蔽所有输出(正在使用的文件删不掉会报一堆红字,太吵)存成 clean-temp.bat,双击就跑。 显式指定用户 Temp 有时想清另一个账户的 Temp,或者用完整路径更保险: @echo off setlocalset USER_NAME=%USERNAME% set USER_TEMP=C:\Users\%USER_NAME%\AppData\Local\Tempecho 清理目录: %USER_TEMP%del /f /s /q "%USER_TEMP%\*" >nul 2>&1 for /d %%p in ("%USER_TEMP%\*") do rmdir /s /q "%%p" >nul 2>&1echo 完成 pause顺便清系统 Temp(需要管理员) C:\Windows\Temp 里的东西也可以清,但必须以管理员运行: del /f /s /q "C:\Windows\Temp\*" >nul 2>&1 for /d %%p in ("C:\Windows\Temp\*") do rmdir /s /q "%%p" >nul 2>&1自动申请管理员权限 想双击就自动 UAC 提升,脚本开头加: @echo off :: 检查是否管理员,不是就重新以管理员启动 net session >nul 2>&1 if %errorlevel% neq 0 ( powershell -Command "Start-Process '%~f0' -Verb RunAs" exit /b )setlocal del /f /s /q "%TEMP%\*" >nul 2>&1 for /d %%p in ("%TEMP%\*") do rmdir /s /q "%%p" >nul 2>&1 del /f /s /q "C:\Windows\Temp\*" >nul 2>&1 echo 完成 pause计划任务:开机自动清 想让开机就跑: schtasks /create /tn "CleanTemp" /tr "C:\path\to\clean-temp.bat" /sc onlogon或者每天 3 点跑: schtasks /create /tn "CleanTemp" /tr "C:\path\to\clean-temp.bat" /sc daily /st 03:00删除任务: schtasks /delete /tn "CleanTemp" /f会看到的"报错" 跑完总有一堆"访问被拒绝"或"文件被占用"——这是正常的。有些文件是 Chrome、微信、系统服务在用,删不掉就是删不掉,重启后再跑一遍即可。 要看进度,把 >nul 2>&1 去掉就能看到每一步: del /f /s /q "%TEMP%\*"别做的事不要清 C:\Windows 下的其它目录,会把系统搞坏 不要开 del /q "C:\*" /s,字面意思 少用 rmdir /s /q C:\Windows\Temp 整个删掉目录本身——某些系统组件会因为找不到目录而报错一句话总结 del %TEMP%\* + for /d %%p rmdir %%p 就是 Temp 清理的核心两行。加个自动 UAC 和计划任务,就能忘掉这事。
