在 bash 中如何避免在变量中扩展特定空间?
可以说我有这个
JAVA_OPTS="-Xmx1g"
JAVA_OPTS="$JAVA_OPTS -XX:OnError='/path/to/a/script.sh %p'"
function args() {
printf "%d :" $#
printf " <%s> " $@
echo
}
args $JAVA_OPTS
你明白了
3 : <-Xmx1g> <-XX:OnError='/path/to/a/script.sh> <%p'>
我想要这个
2 : <-Xmx1g> <-XX:OnError='/path/to/a/script.sh %p'>
答案1
首先请注意,args
即使您只给出一个参数,也会显示两个参数:
$ args "abc def"
1 : <abc> <def>
为了使其正确显示,需要添加双引号:
$ function args() { printf "%d :" $#; printf " <%s> " "$@"; echo; }
$ args "abc def"
1 : <abc def>
然而, 的定义仍然存在问题JAVA_OPTS
。观察:
$ args $JAVA_OPTS
3 : <-Xmx1g> <-XX:OnError='/path/to/a/script.sh> <%p'>
这是因为,当$JAVA_OPTS
出现在命令行上时,shell 将对 JAVA_OPTS 的内容进行分词,但它不会尊重或处理其中包含的引号。
对于这种类型的应用程序,将 JAVA_OPTS 定义为 bash 数组会更好:
$ JAVA_OPTS="-Xmx1g"
$ JAVA_OPTS=("$JAVA_OPTS" "-XX:OnError=/path/to/a/script.sh %p")
$ args "${JAVA_OPTS[@]}"
2 : <-Xmx1g> <-XX:OnError=/path/to/a/script.sh %p>
顺便说一句,在使用数组时,查看数组中内容的便捷方法是declare -p
:
$ declare -p JAVA_OPTS
declare -a JAVA_OPTS='([0]="-Xmx1g" [1]="-XX:OnError=/path/to/a/script.sh %p")'
答案2
你必须使用一个大批反而:
declare -a JAVA_OPTS
JAVA_OPTS+=("-Xmx1g")
JAVA_OPTS+=("-XX:OnError='/path/to/a/script.sh %p'")
args "${JAVA_OPTS[@]}"
一旦字符串中包含某些内容,您就无法选择哪些空格将用于分词,但是使用数组,您可以决定何时将它们放入以及何时将它们再次取出。您也需要$@
在内部引用args
,否则它会损坏。
如果您确实必须使用单个字符串定义它,您可以使用不同的字符来分割元素并重置IFS
:
JAVA_OPTS="-Xmx1g"
JAVA_OPTS="$JAVA_OPTS|-XX:OnError='/path/to/a/script.sh %p'")
IFS="|"
args $JAVA_OPTS
在这种情况下也会做正确的事情,尽管它非常脆弱。与以往一样,您希望保存并重置IFS
,或者仅在子 shell 中进行更改。
答案3
您可以给 shell 的解析器再次传递:
var="'-Xmx1g' \"-XX:OnError='/path/to/a/script.sh %p'\""
eval "echo $var"
输出
-Xmx1g -XX:OnError='/path/to/a/script.sh %p'
但数组可能是最好的:
set -- '-Xmx1g "-XX:OnError='/path/to/a/script.sh %p'"
echo "item count $#"
for i do
echo "item#$((n=$n+1)): $i"
done
echo "$@"
输出
item count 2
item#1: -Xmx1g
item#2: -XX:OnError='/path/to/a/script.sh %p'
-Xmx1g -XX:OnError='/path/to/a/script.sh %p'
尽管它们不一定是相互排斥的:
eval "set $var"
item count 2
item#1: -Xmx1g
item#2: -XX:OnError='/path/to/a/script.sh %p'
-Xmx1g -XX:OnError='/path/to/a/script.sh %p'
在函数内部 - 比如args()
- 如果你想连接两个参数,你只需重置它的参数数组:
args() {
[ $# -gt 2 ] && {
a=$1; shift
set -- "$a" "$*"
} ; printf "%d :" $#
printf " <%s> " "$@"
echo
}
但这是后勤工作。如果您希望这些变量位于数组中:
args() {
printf "%d :" $#
printf " <%s> " "$@"
echo
}
args "$JAVA_OPTS" "-XX:OnError='/path/to/a/script.sh %p'"
或者对于当前的 shell 数组..
set -- "$JAVA_OPTS" "-XX:OnError='/path/to/a/script.sh %p'"
所有表格输出:
2 : <-Xmx1g> <-XX:OnError='/path/to/a/script.sh %p'>
如果在某个时候您希望添加到数组中:
set -- "$@" "some ne
w arg"
args "$@"
3 : <-Xmx1g> <-XX:OnError='/path/to/a/script.sh %p'> <some ne
w arg>
该阵列与外壳一起提供。你应该使用它。