先声明一句这篇文章不是给你讲 WSL 怎么安装的而是解决一个特别日常、特别烦人的问题——你在 Windows 资源管理器里写好的.sh脚本想拿到 WSL 里跑一下结果双击只能打开记事本右键没有“用 bash 运行”辛辛苦苦拖进终端又变成C:\Users\...这种反斜杠路径bash 直接看不懂。我前前后后试过好几套解法今天一次性整理出来从最省事的拖拽方案到右键菜单全都给你安排上。1. 先搞懂拖拽运行的本质与路径转换1.1 你想要的“拖一下就运行”到底做了什么抛开花里胡哨的操作任何“Windows 拖拽运行 WSL SH 脚本”的方案本质上都逃不过这四步Windows 把被拖拽文件的完整路径作为一个参数传给某个接收程序接收程序调用 WSL再由 WSL 里的 bash 去解释执行这个.sh脚本。听懂这句话你就明白了一个关键点WSL 本身并不支持 Windows 拖拽动作我们做的其实是“把拖拽这个动作翻译成一次命令调用”。既然底层都是拼命令、传参数那方案的核心就只剩下两件事——第一拿到文件路径第二把 Windows 路径转换成 WSL 能识别的路径然后执行。所以我下面给的几套方案不管是用 Windows Terminal、批处理还是右键菜单背后的执行链路都是同一条。明白了这一点后面所有代码在你眼里就不是孤立的技巧而是一个可以随意拆装的“脚本运行器”骨架。1.2 一切麻烦都出在路径格式上为什么拖进去的脚本跑不起来因为 Windows 和 WSL 的路径体系完全不是一个物种。Windows 的路径长这样C:\Users\me\scripts\deploy.shWSL 里看同一个文件长这样/mnt/c/Users/me/scripts/deploy.sh这中间不只是斜杠方向反了连盘符都变了。WSL 默认把 Windows 所有盘符挂载到/mnt目录下所以 C 盘就是/mnt/cD 盘就是/mnt/d。你直接把C:\...丢给 bashbash 只会一脸懵地认为你要找一个叫C:的奇怪命令。更糟的是路径里的空格和中文。Windows 路径带空格太常见了比如C:\Program Files\xx\test.sh如果不做引号保护会被拆成好几个参数。所以一个靠谱的路径转换工具是所有方案里绝对不能省的一环。1.3 wslpath 是路径转换的万能钥匙我第一次做路径转换的时候也想过用字符串替换硬写后来放弃了。因为 WSL 的路径种类比你想的多普通本地路径、UNC 路径、带空格路径、中文路径自己写转换逻辑早晚踩坑。WSL 自带的wslpath命令就是干这个的一句话搞定。在 WSL 终端里这样转换wslpath C:\Users\me\test.sh # 输出 /mnt/c/Users/me/test.sh wslpath -a -u C:\Users\me\test.sh # -a 表示绝对路径-u 表示转成 Unix 风格在 Windows 的 CMD 或 PowerShell 里也可以远程调用 WSL 里的 wslpath这个在批处理脚本里非常常用wsl.exe wslpath -a -u C:\Users\me\test.sh反向转换也顺手说一下在 WSL 里把 Linux 路径转回 Windows 路径wslpath -w /home/me/test.sh # 输出 \\wsl.localhost\Ubuntu\home\me\test.sh记住这个命令后面所有方案都会用到它。你自己不用记盘符大小写怎么转、不用记斜杠替换规则wslpath 全给你处理掉这才是正确姿势。2. 准备脚本换行符、编码和执行权限这些硬门槛路径问题解决了脚本本身还有三个特别阴间的坑不提前处理掉你拖拽运行的时候照样会翻车。2.1 换行符CRLF 和 LF 的坑Windows 里的文本文件默认用\r\n结尾Linux 只认\n。你在 Windows 记事本或某些编辑器里写完的.sh脚本拿到 WSL 里跑经常会报这种错bash: $\r: command not found或者/bin/bash^M: bad interpreter: No such file or directory。这就是 CRLF 换行符在作怪。bash 每读一行末尾都会多一个\r它不认识。解决办法很简单在 WSL 里执行一次sed -i s/\r$// script.sh或者用 VS Code 打开脚本右下角把 CRLF 切换到 LF保存。我个人强烈建议用 VS Code 编辑 WSL 里的脚本配合 Remote-WSL 插件文件直接存在 Linux 文件系统里根本不会有换行符问题。2.2 编码记事本保存导致 shebang 失效第二个坑是编码。Windows 记事本保存文件时如果你选 UTF-8默认是带 BOM 的。而 Linux 下的脚本解析器对 BOM 非常敏感BOM 会直接导致 shebang也就是脚本第一行的#!/bin/bash失效报错信息也很迷惑。推荐的编码永远是UTF-8 无 BOM。在 VS Code 里右下角编码选择 UTF-8 即可如果文件已经带 BOM可以用下面的命令去干净sed -i 1s/^\xEF\xBB\xBF// script.sh中文注释乱码也可能是编码问题但那个不影响执行只是看着难受。真正致命的只有 BOM 和 CRLF。2.3 执行权限在 /mnt/c 下不一定管用在 Linux 里跑脚本通常要chmod x script.sh。但是在 Windows 盘符挂载出来的/mnt/c目录下这个权限不一定会被记住很多时候你 chmod 完了换个会话权限又没了。所以我的建议很直接如果你的脚本放在 Windows 目录下统一用bash script.sh的方式执行不依赖执行权限位。bash 把脚本当作参数读取本来就不需要脚本有 x 权限。这样可以少踩一个隐藏坑。3. 方案一把文件拖进 Windows Terminal 的 WSL 窗口这是我最推荐给所有人的方案因为零配置只要你是用 Windows Terminal 打开的 WSL就天然支持。你要做的只是给终端加一个小助手函数。3.1 Windows Terminal 拖放的真实行为先说实话Windows Terminal 默认并不支持“拖进去自动运行”。你从资源管理器拖一个.sh文件进 WSL 标签页终端会在光标位置插入一段带引号的 Windows 路径比如C:\Users\me\script.sh它只是插入文本不会执行任何东西。但别小看这个行为至少你不用手动敲路径了路径里有空格、中文它也会自动加好引号。我们要做的是给这个路径加一个“接收器”。3.2 自定义 wrun 函数拖入后自动转换并运行在 WSL 终端里编辑你的启动配置nano ~/.bashrc在文件末尾加上这个函数wrun() { if [ $# -eq 0 ]; then echo usage: wrun windows-path-or-dragged-file 2 return 1 fi for winpath in $; do case $winpath in [A-Za-z]:*) up$(wslpath -a -u $winpath 2/dev/null) ;; /mnt/*) up$winpath ;; *) echo [SKIP] 只支持 Windows 路径或 /mnt 路径: $winpath 2 continue ;; esac if [ -z $up ]; then echo [ERROR] 路径转换失败: $winpath 2 continue fi case $up in *.sh) echo [RUN ] $up bash $up ;; *) echo [SKIP] 不是 .sh 文件: $up 2 ;; esac done }保存后执行source ~/.bashrc怎么用很简单在终端里输入wrun加一个空格然后把脚本文件从资源管理器拖进终端窗口路径会自动插入在光标后面此时终端显示的是wrun C:\Users\me\script.sh回车函数会自动把 Windows 路径转换成/mnt/c/Users/me/script.sh然后执行。实测下来路径里的空格、中文都能正常处理Windows Terminal 插入的引号会被 bash 正确解析。3.3 多文件、非 .sh 文件与路径带空格的兜底这个函数我特意做了几个兜底逻辑解释一下for winpath in $支持一次拖入多个文件逐个执行[A-Za-z]:*判断是不是盘符路径/mnt/*判断是不是已经是 WSL 路径其他格式直接跳过case $up in *.sh) ...不是.sh结尾的文件会跳过避免你误拖一个图片进来然后 bash 执行报一堆不知所云的错路径转换失败时明确显示 ERROR不会闷声不响。这里要诚实说一个限制如果你从资源管理器拖入的是 Linux 文件系统里的文件也就是\\wsl$\Ubuntu\...这种 UNC 路径Windows Terminal 插入的格式会比较复杂函数虽然能转但输出路径会变成//wsl.localhost/...这种不太好看。这种场景我建议直接用/mnt/c/...或 Linux 原生路径别绕 UNC。4. 方案二拖到图标/发送到菜单一键运行如果你觉得每次打开终端、敲命令、再回车还是太麻烦那就做一劳永逸的“脚本运行器”。核心思路是做一个批处理文件把文件拖到它上面Windows 会把路径作为参数传给它剩下的转换和执行全部自动完成。4.1 原理拖拽到快捷方式等于传参Windows 有一个很老但非常好用的机制你把文件拖到一个程序或快捷方式上相当于用这个程序打开文件被拖文件的路径会作为命令行参数传给程序。我们只需要一个能接收参数、会调用 WSL 的批处理文件就能实现“拖一下就运行”。4.2 完整 bat 代码run-wsl.bat新建一个文本文件改名为run-wsl.bat注意扩展名是.bat而不是.txt用记事本或 VS Code 打开写入下面内容echo off setlocal EnableDelayedExpansion if %~1 ( echo Drag a .sh file onto this runner. pause exit /b ) :process if %~1 goto done set WINPATH%~1 set WSLPATH set EXT!WINPATH:~-3! if /i not !EXT!.sh ( echo [WARN] Not a .sh file, still try to run. ) for /f delims %%p in (wsl.exe wslpath -a -u !WINPATH! 2^nul) do ( set WSLPATH%%p ) if not defined WSLPATH ( echo [ERROR] Failed to convert path: !WINPATH! shift goto process ) echo [INFO] Run: !WSLPATH! wsl.exe bash !WSLPATH! if errorlevel 1 ( echo [ERROR] Execution failed with code !errorlevel! ) shift goto process :done echo [DONE] endlocal timeout /t 2 nul简单解释几个关键点%~1是去除引号的第一个参数也就是被拖入文件的路径for /f调用wsl.exe wslpath -a -u把C:\...转换成/mnt/c/...输出捕获到WSLPATH变量里shift用来处理一次拖入多个文件的情况循环处理最后一行的timeout /t 2让窗口停留 2 秒不会一闪而过输出内容你还能看到。这个 bat 文件本身不写中文就避免了批处理编码乱码问题。路径含空格的时候wslpath !WINPATH!里的双引号已经包好了实测很稳。4.3 把 run-wsl.bat 放到顺手的位置文件做好了怎么用才顺手三个方式第一放进“发送到”菜单。按下快捷键Win R输入shell:sendto回车会打开一个文件夹。把run-wsl.bat复制进去。之后你在任意.sh文件上右键选择“发送到 → run-wsl.bat”脚本就跑起来了。第二做桌面快捷方式。右键run-wsl.bat→ 创建快捷方式把快捷方式放到桌面。平时直接拖一个.sh文件到快捷方式图标上松开自动执行。第三固定到任务栏。把快捷方式拖到任务栏固定同样支持拖拽执行。不过任务栏上的快捷方式拖拽时鼠标反馈比较迷我还是更推荐“发送到”或者桌面快捷方式。这个方案适合固定、高频的脚本执行场景。缺点是批处理的窗口样式比较丑全是黑底白字不过胜在一键、无脑、不依赖任何额外软件。5. 方案三右键菜单“在 WSL 中运行”如果你已经到了“什么都想右键解决”的阶段那就上最终方案直接在鼠标右键菜单里加一个“在 WSL 中运行”。以后不管是脚本还是任意文件右键一下就能用 WSL 处理。5.1 注册表右键菜单的原理Windows 右键菜单是通过注册表实现的。在HKEY_CLASSES_ROOT\*\shell下面注册一个菜单项它就会出现在所有文件类型的右键菜单里。菜单项下有一个command子键里面写着要执行的命令%1会被替换成被右键文件的完整路径。这里要注意直接在这个命令里写wsl bash是能凑合的但处理路径空格、中文、引号转义特别别扭。所以我选择多一步让命令先调用 PowerShell 脚本再由 PowerShell 去调 WSL。这样逻辑清晰路径也不会被搞坏。5.2 PowerShell 中转脚本run-wsl.ps1新建一个run-wsl.ps1文件内容如下param( [Parameter(Mandatory$true)] [string]$FilePath ) $wslPath wsl.exe wslpath -a -u $FilePath 2$null if ($LASTEXITCODE -ne 0 -or [string]::IsNullOrWhiteSpace($wslPath)) { Write-Host [ERROR] wslpath conversion failed: $FilePath -ForegroundColor Red Read-Host Press Enter to close exit 1 } Write-Host [INFO] WSL path: $wslPath -ForegroundColor Cyan Write-Host ----- output ----- wsl.exe bash $wslPath Write-Host ----- done (exit code: $LASTEXITCODE) ----- Read-Host Press Enter to close exit $LASTEXITCODE这段脚本做了四件事接收右键传入的文件路径、用wsl.exe wslpath做路径转换、执行 bash、最后暂停让你看到输出结果。最后的Read-Host一定要留不然 PowerShell 窗口瞬间关闭你根本看不到脚本报了什么错。你可以给脚本加一个扩展名判断非.sh文件时直接提示跳过if (-not $FilePath.ToLower().EndsWith(.sh)) { Write-Host [WARN] Not a .sh file, still try to run. -ForegroundColor Yellow }5.3 导入注册表与卸载把下面的内容保存为add-wsl-rightkey.reg注意把D:\\Tools\\run-wsl.ps1改成你自己的脚本实际路径Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\*\shell\RunWithWSL] Run with WSL Iconwsl.exe [HKEY_CLASSES_ROOT\*\shell\RunWithWSL\command] powershell.exe -NoProfile -ExecutionPolicy Bypass -File \D:\\Tools\\run-wsl.ps1\ \%1\双击这个.reg文件确认导入。然后你在任意.sh文件上右键就能看到“Run with WSL”菜单。卸载也很简单管理员身份打开 CMD执行reg delete HKEY_CLASSES_ROOT\*\shell\RunWithWSL /f右键菜单立即消失。这里要注意注册表命令里%1一定要用双引号包好否则路径带空格的文件会被拆成多个参数。6. 常见问题排查与几点经验习惯6.1 常见错误速查表我把实际使用中容易碰到的问题整理成一个表方便你排查症状原因处理方式bash: $\r: command not found脚本是 CRLF 换行符执行sed -i s/\r$// script.sh/bin/bash^M: bad interpreter脚本是 CRLF 换行符且 shebang 被污染VS Code 切换 LF 保存Permission denied脚本没有执行权限改用bash script.sh方式执行wslpath: command not found极少数精简发行版没有 wslpath安装 WSL 官方包或手动替换斜杠wsl: command not foundWindows 没装 WSL 或 PATH 异常检查wsl -l -v是否正常中文文件名/内容乱码脚本编码不是 UTF-8 无 BOM用 VS Code 转成 UTF-8 无 BOM文件名带空格被拆成多个参数路径没有用双引号包住所有调用都写成%1或!WINPATH!批处理窗口一闪而过没有暂停命令参考本文加入timeout /t 2拖入终端后路径是\\wsl$\...拖的是 Linux 文件系统里的文件用/mnt/c/...或直接输入 Linux 路径还有一个容易忽略的问题批处理里如果路径中出现了英文感叹号!在启用延迟扩展的 bat 里会丢字符。虽然不常见但如果你脚本路径很奇葩记得避开感叹号或者不要用延迟扩展。6.2 我的几个使用习惯方案都给你了最后分享几点我用了很久之后沉淀下来的习惯。第一高频脚本不要放在/mnt/c下面而是直接放在 WSL 的 Linux 文件系统里比如/home/me/bin/。从资源管理器访问这个目录可以用\\wsl$\Ubuntu\home\me\bin。这样做的好处是 IO 性能比跨系统文件访问快得多权限也更符合 Linux 习惯不会出现 chmod 不生效的问题。第二所有脚本开头统一加上#!/usr/bin/env bash和set -euo pipefail。前者兼容不同的 bash 安装位置后者让脚本在出错时快速失败不容易“带病运行”。第三我平时最常用的其实还是wrun函数加右键菜单这两样bat 那个更多是给同事临时救急用的。因为日常开发本来就在 Windows Terminal 里输入wrun再拖文件几乎已经是肌肉记忆而右键菜单适合偶尔处理一下别人发的脚本不用打开任何终端。至于你自己用哪种看你平时的操作习惯但底层思路都是一样的拿到路径用 wslpath 转换再用 bash 执行。第四如果遇到“拖进去之后光标位置不对”的情况先点一下终端窗口让光标停在你想要的位置再拖文件。Windows Terminal 的拖放路径会插在当前光标处这个细节看起来小实际体验差距很大。
阅读完成 · 觉得有帮助?