防止变量中的特定空间被扩展

防止变量中的特定空间被扩展

在 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> 

该阵列与外壳一起提供。你应该使用它。

相关内容