Uma expansão de parâmetro pode funcionar dentro de outra expansão de parâmetro? [duplicado]

0
$ s=/the/path/foo.txt

podemos extrair por critérios diferentes separadamente

$ echo ${s##*/}
foo.txt
$ echo ${s%.txt}
/the/path/foo

Mas se quisermos extrair de acordo com ambos os critérios ao mesmo tempo,

$ echo ${${s##*/}%.txt}
bash: ${${s##*/}%.txt}: bad substitution

É possível alcançar o mesmo objetivo, usando apenas a expansão de parâmetros e sem introduzir uma variável temporária?

Uma expansão de parâmetro pode funcionar dentro de outra expansão de parâmetro de alguma forma?

Obrigado.

    
por Tim 08.01.2018 / 07:12

2 respostas

4

Não e sim. No Bash ou no shell padrão, a primeira parte da expansão deve ser um parâmetro (ou seja, um parâmetro variável ou posicional, ou um dos parâmetros especiais), não qualquer palavra.

Bash :

The basic form of parameter expansion is ${parameter}. The value of parameter is substituted. The parameter is a shell parameter as described above or an array reference.

O texto no POSIX também menciona apenas parâmetros.

Você pode usar uma expansão nas outras partes das expansões, pois elas podem ser palavras arbitrárias. Mas isso, claro, não ajuda no encadeamento de manipulações da mesma string (como no seu exemplo ${${s##*/}%.txt} )

$ bash -c 's=/the/path/foo.txt; ext=.tyt; echo "${s%${ext/y/x}}"'
/the/path/foo

O Zsh suporta explicitamente o encadeamento, embora:

If a ${...} type parameter expression or a $(...) type command substitution is used in place of name above, it is expanded first and the result is used as if it were the value of name.

    
por 08.01.2018 / 09:39
1

Se você estiver procurando o componente de nome de arquivo sem extensão (por exemplo, foo ) como uma única operação, poderá usar uma correspondência RE para extraí-lo do caminho:

s=/the/path/foo.txt
[[ "$s" =~ (.*/)?(.*)\. ]]

echo "Got > ${BASH_REMATCH[2]} <"    # "Got > foo <"

Não encontrei uma maneira de remover a extensão desconhecida mais curta de um nome de arquivo como foo.bar.txt enquanto ainda manipulava um componente de nome de arquivo sem nenhuma extensão (por exemplo, foo ), a menos que você aceite um expressão composta:

[[ "$s" =~ (.*/)?(.*)(\.[^.]*)$ ]] || [[ "$s" =~ (.*/)?(.*) ]]

E se você fizer isso, seria mais eficiente realizar duas substituições consecutivas e ir embora:

s=/path/to/foo
f=${s##*/}
echo "${f%.*}"
    
por 08.01.2018 / 12:49

Tags