取消

了解 Windows/Linux 下命令行/Shell 启动程序传参的区别,这下不用再担心 Windows 下启动程序传参到 Linux 下挂掉了

启动某个程序,再带上一堆参数,这几乎是程序员们每天必做到事情。另外再算上各种辅助程序员们的自动化脚本,辅助构建的 CI(持续集成)等等,程序员们在创造大量的应用程序然后调用它们。

但是,不经常跨系统玩这些的小伙伴们注意了,Windows 下的 Shell 和 Linux 下的 Shell 是有区别的!如果你不了解这些区别,很容易造成在 Windows 下编写的代码/脚本在 Linux 下无法使用的问题。

本文列举 Windows/Linux 下 Shell 的区别。


分号(;)

分号(;)在 Linux 的 Shell 中是不同命令的分割,而在 Windows 中只是一个普通的字符。

例如:

1
dotnet build;dotnet pack

这在 Linux 中是执行两句不同的命令,dotnet builddotnet pack。而换到 Windows 中,这变成了执行 dotnet 程序,然后传入 build;dotnet pack 这个参数。

相反的:

1
foo --tags NET48;NETCOREAPP3_1;RELEASE

这在 Windows 下是启动 foo 程序,然后传入 NET48;NETCOREAPP3_1;RELEASE,而在 Linux 下则变成了执行三个不同的命令。后面两个显然不是命令,于是执行时会报 127 错误:Command not found。(程序执行完成退出,返回值为 127。)

如果你希望你的执行脚本跨平台,那么:

  1. 不要使用分号 ; 来尝试将两个或多个不同的命令合并成 1 行,直接执行多个命令即可。
  2. 如果命令名称或参数中存在分号,则必须使用引号 " 将它包裹起来。

路径空格

Windows 下针对路径中包含空格的情况,用引号包裹路径:

1
"C:\Program Files\Walterlv\Foo.exe"

Linux 下,如果路径中包含空格,则有三种不同的解决策略:

1
2
3
4
5
6
7
8
# 加 \ 转义
/mnt/c/Program\ Files/Walterlv/Foo

# 加双引号
"/mnt/c/Program Files/Walterlv/Foo"

# 加单引号
'/mnt/c/Program Files/Walterlv/Foo'

可以发现,两者都有的方案是加双引号。所以,如果希望你的命令脚本跨平台使用,则应该使用双引号包裹路径。

路径分隔符

Windows 下,\/ 都是路径分隔符。Linux 下,只有 / 是路径分隔符,\ 是合理的文件名,在 Shell 中,\ 是转义字符。

虽然理论上所有路径都使用 / 可以让你的跨平台脚本在以上所有系统中正常工作,但考虑到 Windows 可能有一些逗比程序对 / 支持不好,更建议:

  • 在所有场景下生成路径字符串时使用当前平台的路径分隔符
  • 不要将某平台生成的路径分隔符直接拿到另一平台使用

关于跨平台路径分隔符的问题,我专门写了一篇博客,在那里可以了解更多:

其他特殊字符( ( $ { * #

在 Linux 的 Shell 中,有很多字符有特殊用途,而在 Windows Shell 中,这些字符的作用完全由被调用的应用程序来决定。

所以对于跨平台的脚本,最好尽量避免使用这些字符。

关于 Linux 下这些转义字符的用途,可以阅读我的另一篇博客:

本文会经常更新,请阅读原文: https://blog.walterlv.com/post/typing-difference-among-shells-in-different-operating-systems.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

知识共享许可协议

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 吕毅 (包含链接: https://blog.walterlv.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 ([email protected])

登录 GitHub 账号进行评论