Como o Bash manipula aspas na seção de substituição de string da expansão de parâmetro?

5

Existe alguma lógica consistente para isso?

some-command "${somevariable//some pattern/'how does this get parsed?'}"

Eu postei algumas conclusões e testes brutos abaixo como uma "resposta", mas eles não são uma resposta completa por qualquer meio. A página man do Bash aparece em silêncio sobre o assunto.

    
por Wildcard 15.12.2017 / 06:58

2 respostas

4

Como discutido nos comentários, isso parece ter mudado entre as versões do Bash. Penso que esta é a mudança relevante em bash-4.3-alpha ( changelog ):

zz. When using the pattern substitution word expansion, bash now runs the replacement string through quote removal, since it allows quotes in that string to act as escape characters. This is not backwards compatible, so it can be disabled by setting the bash compatibility mode to 4.2.

E a descrição para shopt -s compat42 ( manual online ) :

compat42
If set, bash does not process the replacement string in the pattern substitution word expansion using quote removal.

O exemplo de aspas simples:

$ s=abc\'def; echo "'${s//\'/\'\\'\'}'"
'abc'\''def'

$ shopt -s compat42
$ s=abc\'def; echo "'${s//\'/\'\\'\'}'"
'abc\'\'\'def'

$ bash --version | head -1
GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu)

Solução: coloque a cadeia de substituição em uma variável, e não uso aspas dentro da substituição:

$ shopt -s compat42
$ qq="'\''"; s=abc\'def; echo "'${s//\'/$qq}'";
'abc'\''def'
$ qq="'\''"; s=abc\'def; echo "'${s//\'/"$qq"}'";
'abc"'\''"def'

O engraçado é que, se a expansão é unquoted , em seguida, as aspas são removidas após a substituição, em todas as versões. Isso é s=abc; echo ${s/b/""} imprime ac . Isto obviamente não acontece com outras expansões, e. s='a""c' ; echo ${s%x} outputs a""c .

    
por 15.12.2017 / 13:00
1

Regras gerais por engenharia reversa:

  • As cotações devem ser acopladas (concluídas)
  • As cotações são preservadas (incluídas na substituição real)
  • As barras invertidas são preservadas se vierem antes de uma letra arbitrária
  • As barras invertidas são preservadas se elas escaparem de uma única citação
  • Uma sequência de barra invertida de barra invertida é reduzida a uma barra invertida, mesmo entre aspas simples
  • Você não pode escapar de uma aspa entre aspas simples
  • A expansão de parâmetros funciona dentro de aspas simples, o mesmo que fora
  • Se um sinal de dólar for escapado com uma barra invertida, o cifrão será preservado literalmente e a barra invertida será removida

E uma conclusão:

  • Não há absolutamente nenhuma maneira de produzir a seqüência literal '\'' como uma substituição por meio da expansão de parâmetro.
  • No entanto, é muito fácil produzir a sequência literal "'\''" como uma substituição.

Alguns testes brutos seguem.

[vagrant@localhost ~]$ echo "$0"
-bash
[vagrant@localhost ~]$ echo "${0//a/x}"
-bxsh
[vagrant@localhost ~]$ echo "${0//a/some long string  with spaces}"
-bsome long string  with spacessh
[vagrant@localhost ~]$ echo "${0//a/"quoted string"}"
-b"quoted string"sh
[vagrant@localhost ~]$ echo "${0//a/"unfinished quote}"
> wat
> }"
-b"unfinished quote}"
wat
sh
[vagrant@localhost ~]$ echo "${0//a/\"escaped quote}"
-b"escaped quotesh
[vagrant@localhost ~]$ echo "${0//a/\escaped escape}"
-b\escaped escapesh
[vagrant@localhost ~]$ echo "${0//a/\'escaped single quote}"
-b\'escaped single quotesh
[vagrant@localhost ~]$ echo "${0//a/''}"
-b''sh
[vagrant@localhost ~]$ echo "${0//a/''''}"
-b''''sh
[vagrant@localhost ~]$ echo "${0//a/'''}"
> a'b}c"d
-b'''}"
a'bshcd
[vagrant@localhost ~]$ echo "${0//a/'''}"
> w'x}y"z
-b'''}"
w'xshyz
[vagrant@localhost ~]$ echo "${0//a/'\'\"a test'\'}"
> ^C
[vagrant@localhost ~]$ echo "${0//a/'\''\"a test'\'}"
-b'\''\"a test'\'sh
[vagrant@localhost ~]$ echo "${0//a/'\''\"a test'\
[vagrant@localhost ~]$ echo "$0"
-bash
[vagrant@localhost ~]$ echo "${0//a/x}"
-bxsh
[vagrant@localhost ~]$ echo "${0//a/some long string  with spaces}"
-bsome long string  with spacessh
[vagrant@localhost ~]$ echo "${0//a/"quoted string"}"
-b"quoted string"sh
[vagrant@localhost ~]$ echo "${0//a/"unfinished quote}"
> wat
> }"
-b"unfinished quote}"
wat
sh
[vagrant@localhost ~]$ echo "${0//a/\"escaped quote}"
-b"escaped quotesh
[vagrant@localhost ~]$ echo "${0//a/\escaped escape}"
-b\escaped escapesh
[vagrant@localhost ~]$ echo "${0//a/\'escaped single quote}"
-b\'escaped single quotesh
[vagrant@localhost ~]$ echo "${0//a/''}"
-b''sh
[vagrant@localhost ~]$ echo "${0//a/''''}"
-b''''sh
[vagrant@localhost ~]$ echo "${0//a/'''}"
> a'b}c"d
-b'''}"
a'bshcd
[vagrant@localhost ~]$ echo "${0//a/'''}"
> w'x}y"z
-b'''}"
w'xshyz
[vagrant@localhost ~]$ echo "${0//a/'\'\"a test'\'}"
> ^C
[vagrant@localhost ~]$ echo "${0//a/'\''\"a test'\'}"
-b'\''\"a test'\'sh
[vagrant@localhost ~]$ echo "${0//a/'\''\"a test'\%pre%'}"
> ^C
[vagrant@localhost ~]$ echo "${0//a/\"a test'\%pre%'}"
> w}x"y
-b\"a test'$0'}"
wshxy
[vagrant@localhost ~]$ echo "${0//a/\\"a test'\%pre%'}"
-b\"a test'$0'sh
[vagrant@localhost ~]$ echo "${0//a/\\"a test'\'$0'}"
> ^C
[vagrant@localhost ~]$ echo "${0//a/\\"a test'\$0'}"
-b\"a test'\-bash'sh
[vagrant@localhost ~]$ 
'}" > ^C [vagrant@localhost ~]$ echo "${0//a/\"a test'\%pre%'}" > w}x"y -b\"a test'$0'}" wshxy [vagrant@localhost ~]$ echo "${0//a/\\"a test'\%pre%'}" -b\"a test'$0'sh [vagrant@localhost ~]$ echo "${0//a/\\"a test'\'$0'}" > ^C [vagrant@localhost ~]$ echo "${0//a/\\"a test'\$0'}" -b\"a test'\-bash'sh [vagrant@localhost ~]$
    
por 15.12.2017 / 06:58