![/bin/sh 不当行为](https://linux22.com/image/177635/%2Fbin%2Fsh%20%E4%B8%8D%E5%BD%93%E8%A1%8C%E4%B8%BA.png)
我正在尝试使用一些简单的标志创建一个运行脚本/bin/sh
#!/bin/sh
set -eux
if [ "$DEBUG" = "true" ]; then
debug="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=$SUSPEND,address=$DEBUG_PORT"
else
debug=''
fi
serv="--server.port=${SERVER_PORT}"
prop="--spring.profiles.active=${PROFILES}"
all="${serv:-} ${prop:-}"
java "${debug:-}"-jar /opt/someJar.jar "${all:-}"
现在我发现了一些我无法解释的问题,也无法在谷歌中找到它为什么会这样。
- 请注意,
"${debug:-}"-jar
没有空间。当我放置一个空格时,应用程序会中断并显示“java 无法找到或加载主类”。当我删除空间时,它会按预期工作。 - 我有两个变量
serv
和prop
。如果我将这两个 as 放在"${serv:-}" "${prop:-}"
java 命令的末尾,那么这两个参数将在应用程序中单独传递。但是当我把"${all:-}"
then 从 java 中的异常中增加时,我可以看到这两个是连接在一起的。
Caused by: java.lang.NumberFormatException: For input string: "1234--spring.profiles.active=some-profile"
但因为它set -eux
打印
+ java -jar /opt/someJar.jar --server.port=1234 --spring.profiles.active=some-profile
这就是我真正想要的。
如果我因任何原因没有提供足够的信息,我可以提供更多信息。我试图实现的目标是理解它为什么会这样,以及如何将其用于/bin/sh
像这样的一些简单脚本。
答案1
Stéphane 提到$@
在普通 shell 中用作数组。这是一种方法:
#!/bin/sh
set -eux
set -- # clear cmdline params
if [ "$DEBUG" = "true" ]; then
set -- "-Xdebug" "-Xrunjdwp:transport=dt_socket,server=y,suspend=$SUSPEND,address=$DEBUG_PORT"
fi
# specify the jar file
set -- "$@" -jar /opt/someJar.jar
# add the port and profile
set -- "$@" "--server.port=${SERVER_PORT}"
set -- "$@" "--spring.profiles.active=${PROFILES}"
# and run it
java "$@"
答案2
sh
没有数组("$@"
位置参数数组除外)。
在:
java "${debug:-}"-jar /opt/someJar.jar "${all:-}"
java
仅传递 3 个参数(除了java
它本身)。
当您打算传递两个参数时,最后一个将包含类似--server.port=1234 --spring.profiles.active=some-profile
嵌入空格的内容:--server.port=1234
和--spring.profiles.active=some-profile
。
A标量(相对于大批) 变量与$all
in一样sh
,只能包含一个值。
相反,您可以将"$@"
数组用作格伦已经表明(我也喜欢混合$IFS
并且noglob
非常混乱)或者你可以告诉 shell分裂通过将变量设置为分隔符来扩展变量的内容$IFS
,并将参数扩展保留为不带引号的(在禁用通配符之后,因为默认情况下也会在不带引号的参数扩展时进行通配符)。
对于$IFS
,您需要选择一个不能出现在参数中的字符,并且如果您想保留空参数,该字符不能是 SPC、TAB 或 NL(所有 3 个字符恰好都在 的默认值中$IFS
)。
然而,在您的情况下,您似乎希望一个空$serv
实例在为空时导致没有相应的参数$serv
(而不是一个空参数),因此空白$IFS
可能是一个更好的主意。 NL 可能是一个不错的选择,因为它不太可能在您的论点中找到:
serv="--server.port=${SERVER_PORT}"
prop="--spring.profiles.active=${PROFILES}"
IFS="
" # newline character only
all="${serv:-}${IFS}${prop:-}"
set -o noglob # disable glob
java ... /opt/someJar.jar $all
您需要为 做类似的事情$debug
。
set -o noglob
如果您可以保证所有参数都不包含通配符、大括号或反斜杠,则可以跳过。
请注意,xtrace
您的 shell 的输出有点误导。它通过原始输出并用 SPC 字符分隔来表示传递给命令的参数列表。这意味着我们无法区分参数中的 SPC 字符和用于xtrace
分隔参数的输出字符。
其他一些 shell 更有用,因为当存在此类歧义时,它们会在参数周围输出引号。
set -x; printf "<%s>\n" foo "bar baz"
比较几个不同 shell 解释时的输出:
$ dash -c 'set -x; printf "<%s>\n" foo "bar baz"'
+ printf <%s>\n foo bar baz
<foo>
<bar baz>
$ bosh -c 'set -x; printf "<%s>\n" foo "bar baz"'
+ printf <%s>\n foo bar baz
<foo>
<bar baz>
$ bash -c 'set -x; printf "<%s>\n" foo "bar baz"'
+ printf '<%s>\n' foo 'bar baz'
<foo>
<bar baz>
$ ksh -c 'set -x; printf "<%s>\n" foo "bar baz"'
+ printf '<%s>\n' foo 'bar baz'
<foo>
<bar baz>
您的sh
似乎属于dash
/bosh
类别。看看他们的+ printf <%s>\n foo bar baz
xtrace 输出如何让您认为printf
正在传递 3 个foo
, bar
,baz
参数,而实际上它正在传递两个参数:foo
和bar baz
。