É possível “proteger” um caractere IFS da divisão de campo?

3

Em um POSIX sh, ou no shell Bourne (como no /bin/sh do Solaris 10), é possível ter algo como:

a='some var with spaces and a special space'
printf "%s\n" $a

E, com o padrão IFS , get:

some
var
with
spaces
and
a
special space

Ou seja, proteger o espaço entre special e space por alguma combinação de cotação ou escape?

O número de palavras em a não é conhecido de antemão, ou eu tentaria algo como:

a='some var with spaces and a special\ space'
printf "%s\n" "$a" | while read field1 field2 ...

O contexto é este bug reportado no Cassandra, onde o OP tentou definir uma variável de ambiente especificando opções para a JVM:

export JVM_EXTRA_OPTS='-XX:OnOutOfMemoryError="echo oh_no"'

No script que está executando o Cassandra, que deve suportar o POSIX sh e o Solaris sh:

JVM_OPTS="$JVM_OPTS $JVM_EXTRA_OPTS"
#...
exec $NUMACTL "$JAVA" $JVM_OPTS $cassandra_parms -cp "$CLASSPATH" $props "$class"

IMO, a única maneira é usar um script envolvendo o comando echo oh_no . Existe outro jeito?

    
por muru 24.10.2016 / 07:50

2 respostas

4

Não realmente.

Uma solução é reservar um personagem como separador de campo. Obviamente, não será possível incluir esse caractere, seja lá o que for, em uma opção. Tab e newline são candidatos óbvios, se o idioma de origem facilitar a sua inserção. Eu evitaria caracteres multibyte se você quiser portabilidade (por exemplo, dash e BusyBox não suportam caracteres multibyte).

Se você confiar na divisão do IFS, não se esqueça de desativar a expansão de curinga com set -f .

tab=$(printf '\t')
IFS=$tab
set -f
exec java $JVM_EXTRA_OPTS …

Outra abordagem é introduzir uma sintaxe de cotação. Uma sintaxe de citação muito comum é que uma barra invertida protege o próximo caractere. A desvantagem de usar barras invertidas é que muitas ferramentas diferentes o usam como caracteres de aspas, o que pode ser difícil de descobrir quantas barras invertidas você precisa.

set java
eval 'set -- "$@"' $(printf '%s\n' "$JVM_EXTRA_OPTS" | sed -e 's/[^ ]/\&/g' -e 's/\\/\/g') …
exec "$@"
    
por 25.10.2016 / 01:23
2

Se você estivesse usando o Bash ou algo semelhante, um array faria o truque:

a=(some var with spaces and a 'special space')

Mas como o shell POSIX não possui estes, a melhor abordagem interna que eu posso ver é realmente usar um espaço especial. O espaço não separável (U + 00A0) é bem adequado para esse propósito, mas estar fora do ASCII requer concordância no conjunto de caracteres do script.

a="some var with spaces and a special space"
# this is a non-breaking space ------^
echo "$a" \
| while read word; do printf '%s\n' ${word} | sed 's@ @ @g'; done
# this is a non-breaking space ----------------------^

Esta saída:

some
var
with
spaces
and
a
special space

No momento, não tenho certeza de como incluir isso em uma expansão variável (será necessário um subshell), mas isso deve oferecer um ponto de partida para uma investigação mais aprofundada.

    
por 24.10.2016 / 16:56