Evitar que um espaço específico seja expandido em uma variável

4

No bash, como você evita que um espaço específico seja expandido em uma variável?

Digamos que eu tenha isso

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

Você recebe isso

3 : <-Xmx1g> <-XX:OnError='/path/to/a/script.sh> <%p'>

Eu gostaria disso

2 : <-Xmx1g> <-XX:OnError='/path/to/a/script.sh %p'>
    
por Greg Bowyer 15.08.2014 / 08:29

3 respostas

9

Primeiro, observe que args mostrará dois argumentos, mesmo se você der apenas um:

$ args "abc def"
1 : <abc>  <def> 

Para que seja exibido corretamente, é necessário adicionar aspas duplas:

$ function args() { printf "%d :" $#; printf " <%s> " "$@"; echo; }
$ args "abc def"
1 : <abc def> 

No entanto, ainda existem problemas com a definição de JAVA_OPTS . Observe:

$ args $JAVA_OPTS
3 : <-Xmx1g>  <-XX:OnError='/path/to/a/script.sh>  <%p'> 

Isso ocorre porque, quando $JAVA_OPTS aparece em uma linha de comando, o shell fará a divisão de palavras no conteúdo de JAVA_OPTS, mas não respeitará nem processará as aspas contidas nele.

Para este tipo de aplicativo, você está muito melhor com JAVA_OPTS definido como um array 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>

A propósito, ao trabalhar com arrays, uma maneira prática de ver o que está neles é com declare -p :

$ declare -p JAVA_OPTS
declare -a JAVA_OPTS='([0]="-Xmx1g" [1]="-XX:OnError=/path/to/a/script.sh %p")'
    
por 15.08.2014 / 09:09
4

Você precisa usar uma matriz :

declare -a JAVA_OPTS
JAVA_OPTS+=("-Xmx1g")
JAVA_OPTS+=("-XX:OnError='/path/to/a/script.sh %p'")
args "${JAVA_OPTS[@]}"

Quando algo está em uma string, não é possível escolher quais espaços serão usados para a divisão de palavras, mas, com uma matriz, você pode decidir quando colocá-los e retirá-los novamente. Você também deseja citar $@ dentro de args ou ele será quebrado.

Se você realmente deve defini-lo usando uma única string, você pode usar um caractere diferente para dividir elementos e redefinir IFS :

JAVA_OPTS="-Xmx1g"
JAVA_OPTS="$JAVA_OPTS|-XX:OnError='/path/to/a/script.sh %p'")
IFS="|"
args $JAVA_OPTS

também fará a coisa certa neste caso, embora seja bem frágil. Como sempre, você deseja salvar e redefinir IFS ou apenas fazer a alteração em uma subcamada.

    
por 15.08.2014 / 09:12
-1

Você pode dar ao analisador do shell outro passe:

var="'-Xmx1g' \"-XX:OnError='/path/to/a/script.sh %p'\"" 
eval "echo $var"

OUTPUT

-Xmx1g -XX:OnError='/path/to/a/script.sh %p'

Mas uma matriz provavelmente é melhor:

set -- '-Xmx1g "-XX:OnError='/path/to/a/script.sh %p'"

echo "item count $#"
for i do 
    echo "item#$((n=$n+1)): $i"
done
echo "$@" 

OUTPUT

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'

Embora não sejam necessariamente mutuamente exclusivos:

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'

De dentro de uma função - como args() - se você quisesse concatenar dois argumentos, você apenas redefiniria sua matriz de argumentos:

args() {
    [ $# -gt 2 ] && {
        a=$1; shift 
        set -- "$a" "$*" 
} ; printf "%d :" $#
    printf " <%s> " "$@"
    echo
}

Mas isso é trabalho de retaguarda. Se você quiser essas variáveis em uma matriz:

args() {
    printf "%d :" $#
    printf " <%s> " "$@"
    echo
}

args "$JAVA_OPTS" "-XX:OnError='/path/to/a/script.sh %p'"

ou para o atual array de shell ..

set -- "$JAVA_OPTS" "-XX:OnError='/path/to/a/script.sh %p'"

Saída de todos os formulários:

2 : <-Xmx1g>  <-XX:OnError='/path/to/a/script.sh %p'> 

E se em algum momento você quiser adicionar ao array:

set -- "$@" "some ne
w arg"
args "$@"
3 : <-Xmx1g>  <-XX:OnError='/path/to/a/script.sh %p'>  <some ne
w arg> 

O array vem com o shell. Você deveria usá-lo.

    
por 15.08.2014 / 10:12