
Em um sh POSIX, ou no shell Bourne (como no Solaris 10 /bin/sh
), é possível ter algo como:
a='some var with spaces and a special space'
printf "%s\n" $a
E, com o padrão IFS
, obtenha:
some
var
with
spaces
and
a
special space
Ou seja, proteger o espaço entre special
e space
com alguma combinação de citação ou escape?
O número de palavras 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 éesse bugrelatado em 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 executa Cassandra, que deve suportar POSIX sh e Solaris sh:
JVM_OPTS="$JVM_OPTS $JVM_EXTRA_OPTS"
#...
exec $NUMACTL "$JAVA" $JVM_OPTS $cassandra_parms -cp "$CLASSPATH" $props "$class"
IMO, a única saída aqui é usar um script que envolva o echo oh_no
comando. Existe outra maneira?
Responder1
Na verdade.
Uma solução é reservar um caractere como separador de campos. Obviamente não será possível incluir esse personagem, seja ele qual for, numa opção. Tabulação e nova linha são candidatos óbvios, se o idioma de origem facilitar sua inserção. Eu evitaria caracteres multibyte se você quiser portabilidade (por exemplo, dash e BusyBox não suportam caracteres multibyte).
Se você depende da divisão IFS, não se esqueça de desativar a expansão 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 cotação muito comum é que uma barra invertida protege o próximo caractere. A desvantagem de usar barras invertidas é que tantas ferramentas diferentes as utilizam como caracteres de citação que às vezes pode ser difícil descobrir quantas barras invertidas você precisa.
set java
eval 'set -- "$@"' $(printf '%s\n' "$JVM_EXTRA_OPTS" | sed -e 's/[^ ]/\\&/g' -e 's/\\\\/\\/g') …
exec "$@"
Responder2
Se você estivesse usando Bash ou similar, um array resolveria o problema:
a=(some var with spaces and a 'special space')
Mas como o shell POSIX não possui isso, a melhor abordagem interna que posso ver é usar um espaço especial. O espaço inseparável (U+00A0) é adequado para esse propósito, mas estar fora do ASCII requer acordo sobre o 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 ----------------------^
Isso produz:
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.