変数の特定のスペースが拡張されるのを防ぐ

変数の特定のスペースが拡張されるのを防ぐ

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

最初にargs1つの引数だけを指定しても、2つの引数が表示されます。

$ 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これは、シェルがコマンドラインに表示されたときに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たり、サブシェルで変更をしたいと思います。

答え3

再びシェルのパーサーを渡すことができます:

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()2つの引数を連結するには、その引数の配列をリセットします。

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'"

または現在のシェル配列の場合..

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> 

アレイはエンクロージャに付属しています。あなたはそれを使用する必要があります。

関連情報