这可能是重复的,但我发现答案的最初问题并没有解决问题。
问题的另一个重写。
我有这个Java应用程序:
public static void main(final String[] args) {
System.out.println("DEBUG: arguments passed to the main - " + Arrays.toString(args));
System.exit(new TaskRunner().run(args));
}
如果我直接用两个参数调用代码:
$ nohup ${JAVA_HOME}/bin/java -cp /opt/fxudply/fxcal-client-jar/current/lib:/opt/fxudply/fxcal-client-jar/current/lib/*:/opt/fxudply/fxcal-config/current/wib-config:/opt/fxudply/fxcal-config/current/wib-config/* wib.runner.TaskRunner -taskExtRef "QUOTES_UPLOAD IPV - EOD Rates Input - Commodities Volatilities" > /opt/sw/calypso/logs/taskrunner/log.direct.log 2>&1
它打印
[TaskRunner] DEBUG: : arguments passed to the main - [-taskExtRef, QUOTES_UPLOAD IPV - EOD Rates Input - Commodities Volatilities]
这正是我所期望的。但如果我写这个 shell 脚本 ( startScheduledTask.sh
):
NOW_DATE=`date '+%Y%m%d%H%M%S'`
nohup ${JAVA_HOME}/bin/java -cp some:classpath:values package.name.classname "$@" > /opt/random/path/tplogs/classname/${aVariableLogName}.${NOW_DATE}.log 2>&1
并将其运行为
$ ./startScheduledTask.sh -taskExtRef "QUOTES_UPLOAD IPV - EOD Rates Input - Commodities Volatilities" &
我得到这个输出:
[TaskRunner] DEBUG: : arguments passed to the main - [-taskExtRef, QUOTES_UPLOAD, IPV, -, EOD, Rates, Input, -, Commodities, Volatilities]
(即,第二个参数被分解为九个参数,因为它包含八个空格)。因此我认为剧本有问题。
我该如何解决?
答案1
当 shell 解析命令行时,它会删除引号,但会记住它们所暗示的文本结构。 (这是一种严重的过于简单化;参见重击(1)或者外壳命令语言了解更多详细信息。)例如,命令行输入
-blah apple -secondfruit "green banana" -some more
使 shell 识别六个单词或标记:
-blah
apple
-secondfruit
green banana
-some
more
它将被存储在内存中
-blahⓧappleⓧ-secondfruitⓧgreen bananaⓧ-someⓧmoreⓧ
其中ⓧ
表示空字节。有时这会显示或报告为
-blah apple -secondfruit green banana -some more
所以你可能会认为引号只是被忽略了,而你有七个单词,而事实上,你已经有了你想要的。
笔记:
上式中,
ⓧ
代表空字节。我在这里描述的是标准shell 参数解析处理。如果您输入ls -l fruit.sh "I came here for an argument" startScheduledTask.sh
/bin/ls
使用字符串调用程序lsⓧ-lⓧfruit.shⓧI came here for an argumentⓧstartScheduledTask.shⓧ
在内存中,这被解释为
- argv[0] =
ls
- argv[1] =
-l
- argv[2] =
fruit.sh
- argv[3] =
I came here for an argument
- argv[4] =
startScheduledTask.sh
这完全相同的过程如果你是的话就会发生
java
直接在主交互式 shell 中输入命令,- 执行
java
shell 脚本中的命令,或者./startScheduledTask.sh
通过直接在主交互式 shell 中键入命令来运行 shell 脚本,所以这不是问题。 任何无法处理其参数由空字符分隔的程序 无法在 Unix 和 Linux 中工作。
长话短说
你的第一个命令是正确的。 "$@"
给你你想要的;这是 shell 脚本将其参数传递给它调用的程序的正确方法。如果您将调试代码添加到程序中以循环遍历其参数,将每个参数打印在新行和/或括号中(但不是全部打印在一行上,仅用空格分隔),您将看到正在"$@"
传递六个参数到程序。
好吧,还有更多:
你的类路径有星号(
*
s) 在里面?真的吗?我对 Java 有点不太熟悉,但这对我来说似乎很奇怪。请仔细检查您的系统是否正确执行了该操作。但是,如果当您“直接”输入带有星号的类路径(即直接进入您的主 shell;您的主要交互式 shell;您的登录 shell)时它可以正常工作,那么那就是大概不是问题。但无论如何,请幽默我并将该字符串放入引号中。
你的问题太复杂了。当你建造一架飞机时,你不会建造整个飞机然后尝试驾驶它。然后,当它不飞时,你不会退后一步问:“飞机出了什么问题?”不,你要分块测试它。你需要简化。
- 停止在后台运行它。
- 别说了
nohup
。 - 停止重定向输出。
- 不要在问题中显示 42 个字符的长 shell 提示符。
- 你的问题是关于一个参数中包含空格,所以不要将其删除,但它不必是 60 个字符长且包含 8 个空格。
green banana
是一个伟大的测试值。 - 尝试使用程序的参数不是以。。。开始
-
(短跑)。 - 甚至可以注释掉
new TaskRunner().run(args)
程序的一部分,只留下 DEBUG 和System.exit(0);
.
都不是应该做出改变。但它们会让人分心,让人很难看清重要的事情。如果您可以在最小的测试配置中演示该问题,我们就可以排除与该问题相关的所有其他事情。但是,如果删除不相关的内容后问题消失了,那么问题可能是其中之一引起的。
另外,请停止在问题中混合假/测试数据和真实数据(即水果和任务)。
请编写这个脚本(称之为
fruity.sh
):#!/bin/sh # classpath CP="/opt/fxudply/fxcal-client-jar/current/lib:/opt/fxudply/fxcal-client-jar/current/lib/*:/opt/fxudply/fxcal-config/current/wib-config:/opt/fxudply/fxcal-config/current/wib-config/*" # package.name.classname PC=wib.runner.TaskRunner "$JAVA_HOME"/bin/java -cp "$CP" "$PC" "$@"
并运行
./fruity.sh taskExtRef "green banana"
如果调试说
…[taskExtRef, green banana]
那么它
"$@"
工作正常,问题出在脚本的其他地方。尝试找到它。一次进行一项更改,看看行为如何变化。如果您无法弄清楚,我们也许可以帮助您,但前提是您向我们展示脚本中的部分内容导致问题。但如果调试说
…[taskExtRef, green, banana]
然后让我们知道。