Atualmente, estou tentando entender a expansão de parâmetros, especialmente as diferentes formas que podem remover partes do valor de um parâmetro por correspondência de padrões. Por causa desta pergunta, vamos nos concentrar na ${parameter#word}
expansão.
As duas seções relevantes do manual ( man bash
) (ênfase minha):
${parameter#word}
${parameter##word}
Remova o padrão de prefixo correspondente. A palavra é expandida para produzir um padrão exatamente como na expansão do nome do caminho e comparada com o valor expandido do parâmetro usando as regras descritas em Correspondência de padrões abaixo. Se o padrão corresponder ao início do valor do parâmetro, o resultado da expansão será o valor expandido do parâmetro com o padrão de correspondência mais curto (o'#'
caso) ou o padrão de correspondência mais longo (o'##'
caso) excluído. [...]
Expansão
do nome do caminho Após a divisão de palavras, a menos que a opção -f tenha sido definida, o bash verifica cada palavra em busca dos caracteres *, ? e [. Se um desses caracteres aparecer, a palavra será considerada um padrão e substituída por uma lista ordenada alfabeticamente de nomes de arquivos correspondentes ao padrão (consulte Correspondência de padrões abaixo). [...]
No entanto, considere a seguinte parte de uma sessão de terminal:
root@cerberus ~/scripts # mkdir test
root@cerberus ~/scripts # cd test
root@cerberus ~/scripts/test # touch foo
root@cerberus ~/scripts/test # String=foobar
root@cerberus ~/scripts/test # printf '%s\n' ${String#foo}
bar
root@cerberus ~/scripts/test # printf '%s\n' ${String#*}
foobar
root@cerberus ~/scripts/test #
Não consigo entender a saída após o último comando. De acordo com o manual, o *
deve ser expandido para foo
, pois foo
é o único arquivo no diretório atual; pelo menos, esta é a minha noção de "produzir um padrão como na expansão do nome do caminho".
Portanto, neste caso, printf '%s\n' ${String#*}
deve dar a mesma saída que printf '%s\n' ${String#foo}
.
Obviamente, este não é o caso. Onde está meu mal-entendido?
Sobre a correspondência de padrões :
E, na expansão de parâmetros para remoção de substring,
#
faz a correspondência mais curta, enquanto##
a mais longa.Isso está removendo a string nula (correspondência mais curta) desde o início:
E isso está removendo
foobar
(correspondência mais longa) desde o início:Em relação ao último parágrafo da sua descrição: A remoção de substring com expansão de parâmetros não tem nada a ver com quais arquivos estão em seu diretório atual. O padrão está correspondendo ao valor do parâmetro, não a nenhum arquivo, pense nisso como uma operação de processamento de texto no valor do parâmetro.
Ele pega a parte " word " como um padrão como os usados para geração de nome de arquivo, mas não a usa para geração de nome de arquivo. Em vez disso, o padrão é usado para corresponder ao valor do parâmetro fornecido.
Por exemplo, se você tiver
str=foobsar
,${str#*o}
tente o padrão*o
no início defoobar
, encontrefo
a correspondência mais curta (a*
correspondência com qualquer número de qualquer caractere), remova isso e expanda paraobar
. Da mesma forma${str#*o}
, encontraria a correspondência mais longa,foo
, remova-a em expandbar
.A razão pela qual diz "a palavra está expandida" é que você pode usar expansões na parte " palavra ", assim:
ou
Então, novamente, com a expansão sem aspas como acima, o resultado após a remoção do prefixo passaria por divisão de palavras e globbing. Você provavelmente deve citar toda a expansão para evitar isso, ou seja
"${str#*o}"
, ou qualquer outra coisa.