谁改了我的命令行参数:PowerShell还是Java?

33 篇文章 0 订阅

(一) 现象

某个java程序在传入命令行参数时,虽然大部分情况下正常。
但当参数中有字符*的时候,也可能出现程序收到的参数,对应不上实际命令行参数的情况。
纳尼?从来没遇到过噢。

(二) 分析

不要业务部分,仅编写最简单的测试程序来测试。
测试程序仅仅打印出收到的参数(这也会错?)

输入固定的参数1a 2b 3c 4d "C:\mysql\*" 6e 7f

(2.1) Java

	public static void main(String[] args) {
		for(String aa: args){
			System.out.println(aa);
		}
		System.out.println();
	}

(2.1.1) Java + IntellJ IDEA 调试(正常)

在这里插入图片描述

(2.1.2) Java + CMD(正常)

正常:
在这里插入图片描述

再测试,去掉参数中的双引号。
此时参数 C:\mysql\*这个字符串,变成了目录下列举到的文件名,依次传入程序了。
在这里插入图片描述

(2.1.3) Java + PowerShell(问题)

无论是不是带有引号,均无法把 C:\mysql\*这个字符串传入程序,收到的都是列举目录的多个文件名。
在这里插入图片描述
在这里插入图片描述

(2.2) Python

为了对比,也用Python试了一下。

import sys

if __name__ == "__main__": 
    for aa in sys.argv:
        print(aa) 
    print("")    

(2.2.1) Python + CMD(正常)

在这里插入图片描述

再测试,去掉参数中的双引号。
没有任何变化,并没去列举文件名。
在这里插入图片描述

(2.2.2) Python + PowerShell(正常)

无论是不是带有引号,均不会去列举文件。
在这里插入图片描述
在这里插入图片描述

(三) 总结

到底是Powershell还是Java的锅我理解不了。

(3.1)神奇功能

结论是在Windows中用CMDPowerShell调用Java程序,命令行参数如果带有通配符*?
则会去列举这个字符串的文件,上例相当于dir C:\mysql\*,并把列举到的文件名当作参数传递。
因此破坏了参数的个数检查,打乱了顺序。

仅调用Java时才这样,至少Python是正常的。
呃,可执行程序我准备再试试。

(3.2)引号包围参数

绕开这个神奇功能,可以在CMD中通过双引号包围参数,如:"C:\mysql\*",将参数视为单个字符串传递。
PS:单个参数中如果有空格,也需要用双引号包围。

但是这个办法,在PowerShell下失效了。
无论是否有引号,双引号或单引号(是的,PowerShell比CMD多支持了单引号),它都必须去匹配文件。
除非配备不到文件,才将字符串本身传递(这是什么奇葩逻辑)。

也就是PS根本不遵守引号内的字符串是单个参数,这个基本的约定(可恶的索尼😄)。

(3.3)转义字符

在PowerShell下,参数中如果包含了*?,用转义字符是没有办法转义它的。

而且对于转义字符引号自己,比如刚才的"C:\mysql\*",即使改为"""C:\mysql\*"""看上去正确了,其实也只是匹配不到带引号的"C:\mysql\*"文件而已。
如果换成单引号,换个写法,比如'''*''.txt',是可以匹配到带单引号的文件'A'.txt的。

PS:文件名中确实允许有单引号。

(四) 解决

办法很简答,用微软抛弃的CMD
或者参数复杂点,比如前面带横杠-param--param,而不是直接param。(啥,你喜欢用args?)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值