Como posso usar a expansão de parâmetros? Como posso obter substrings? Como posso obter um arquivo sem sua extensão ou obter apenas a extensão de um arquivo? Quais são algumas boas maneiras de fazer basename e dirname?

Postado 21:40 21/03/2022 por THIAGO CONDÉ COMPARTILHAR

Como posso usar a expansão de parâmetros? Como posso obter substrings? Como posso obter um arquivo sem sua extensão ou obter apenas a extensão de um arquivo? Quais são algumas boas maneiras de fazer basename e dirname?

A expansão de parâmetros é um assunto importante. Esta página contém uma visão geral concisa da expansão de parâmetros.

A Expansão de Parâmetros substitui uma variável ou parâmetro especial por seu valor. É a principal maneira de desreferenciar (referir-se a) variáveis ​​em shells do tipo Bourne, como o Bash. A expansão de parâmetros também pode realizar várias operações no valor ao mesmo tempo por conveniência. Lembre-se de citar suas expansões .

O primeiro conjunto de recursos envolve a remoção de uma substring , do início ou do final de um parâmetro. Aqui está um exemplo usando a expansão de parâmetros com algo semelhante a um nome de host (componentes separados por pontos):

resultado do parâmetro
-----------   ------------------------------
$name polonês.avestruz.corrida.campeão
${name#*.} avestruz.corrida.campeão
${name##*.} campeão
${name%%.**} polimento
${name%.*} polaco.avestruz.corrida

E aqui está um exemplo das expansões de parâmetros para um nome de arquivo típico:

resultado do parâmetro
-----------   --------------------------------------------------------
$file /usr/share/java-1.4.2-sun/demo/applets/Clock/Clock.class
${file#*/} usr/share/java-1.4.2-sun/demo/applets/Clock/Clock.class
${file##*/} Clock.class
${arquivo%%/*}
${file%/*} /usr/share/java-1.4.2-sun/demo/applets/Clock

Os usuários de teclado dos EUA podem achar útil observar que, no teclado, o "#" está à esquerda do símbolo "%". Mnemonicamente, "#" opera no lado esquerdo de um parâmetro e "%" opera no lado direito. glob após o "%" ou "%%" ou "#" ou "##" especifica qual padrão remover da expansão do parâmetro. Outro mnemônico é que em uma frase em inglês "#" geralmente vem antes de um número (por exemplo, "The #1 Bash reference site"), enquanto "%" geralmente vem depois de um número (por exemplo, "Now 5% discounted"), então eles operam nesses lados.

Você não pode aninhar expansões de parâmetros. Se você precisar realizar duas etapas de expansão, use uma variável para armazenar o resultado da primeira expansão:

# foo contém: key="algum valor"
bar=${foo#*=\"} bar=${bar%\"*}
# agora a barra contém: algum valor

Aqui estão mais alguns exemplos (mas consulte a documentação real para obter uma lista de todos os recursos!). Eu as incluo principalmente para que as pessoas não quebrem o wiki novamente, tentando adicionar novas perguntas que respondam a essas coisas.

${string:2:1} # O terceiro caractere da string (0, 1, 2 = terceiro)
${string:1} # A string a partir do segundo caractere
                # Nota: isso é equivalente a ${string#?}
${string%?} # A string com seu último caractere removido.
${string: -1} # O último caractere da string
${string:(-1)} # O último caractere da string, sintaxe alternativa
                # Nota: string:-1 significa algo totalmente diferente; Veja abaixo.

${file%.mp3} # O nome do arquivo sem a extensão .mp3
                # Muito útil em loops do formulário: for file in *.mp3; Faz ...
${file%.*} # O nome do arquivo sem sua última extensão
${file%%.*} # O nome do arquivo sem todas as suas extensões
${file##*.} # Apenas a extensão, assumindo que existe uma. Caso contrário, expandirá para: $file

Exemplos de manipulação de nome de arquivo

Aqui está uma maneira compatível com POSIX de obter um nome de caminho completo, extrair o componente de diretório do nome do caminho, o nome do arquivo, apenas a extensão, o nome do arquivo sem a extensão (o "stub"), qualquer parte numérica que ocorra no final do stub (ignorando quaisquer dígitos que ocorram no meio do nome do arquivo), execute aritmética nesse número (neste caso, incrementando em um) e remonte o nome do arquivo inteiro adicionando um prefixo ao nome do arquivo e substituindo o número no nome do arquivo por outro .

FullPath=/path/to/name4afile-009.ext # resultado: # /path/to/name4afile-009.ext
Filename=${FullPath##*/} # name4afile-009.ext
PathPref=${FullPath%"$Filename"} # /path/to/
FileStub=${Filename%.*} # name4afile-009
FileExt=${Filename#"$FileStub"} # .ext
FnumPossLeading0s=${FileStub##*[![:digit:]]} # 009
FnumOnlyLeading0s=${FnumPossLeading0s%%[!0]*} # 00
FileNumber=${FnumPossLeading0s#"$FnumOnlyLeading0s"} # 9
NextNumber=$(( FileNumber + 1 )) # 10
NextNumberWithLeading0s=$(printf "%0${#FnumPossLeading0s}d" "$NextNumber")
                                                     #   010
FileStubNoNum=${FileStub%"$FnumPossLeading0s"} # name4afile-
NewFullPath = $ PathPref} Novo _ $  $ {NextNumberWithLeading0s $ {FileExt
                        # O resultado final é: # /path/to/New_name4afile-010.ext

Observe que tentar obter o componente de diretório do nome do caminho com PathPref="${FullPath%/*}" não retornará uma string vazia se $FullPath for "SomeFilename.ext" ou algum outro nome de caminho sem uma barra. Da mesma forma, tentar obter a extensão do arquivo usando FileExt="${Filename#*.}" falha ao retornar uma string vazia se $Filename não tiver ponto (e, portanto, nenhuma extensão).

Observe também que é necessário se livrar dos zeros à esquerda para $FileNumber para realizar aritmética, ou então o número é interpretado como octal. Alternativamente, pode-se adicionar um prefixo 10# para forçar a base 10. No exemplo acima, tentar calcular $(( FnumPossLeading0s + 1 )) resulta em um erro, pois "00809" não é um número válido. Se tivéssemos usado "00777" em vez disso, não haveria erro, mas $(( FnumPossLeading0s + 1 )) resultaria em "1000" (já que octal 777 + 1 é octal 1000), o que provavelmente não é o pretendido. Consulte Expressão Aritmética .

A citação não é necessária na atribuição de variáveis, pois o WordSplitting não ocorre. Por outro lado, as variáveis ​​referenciadas dentro de uma expansão de parâmetro precisam ser citadas (por exemplo, quote $Filename in PathPref=${FullPath%"$Filename"} ) ou qualquer * ou ? ou outros caracteres dentro do nome do arquivo incorretamente se tornariam parte da expansão do parâmetro (por exemplo, se um asterisco for o primeiro caractere no nome do arquivo --try FullPath="dir/*filename" ).

Festança 4

O Bash 4 introduziu algumas expansões de parâmetros adicionais: toupper ( ^ ) e tolower ( , ).

# string='Olá, Mundo!'
resultado do parâmetro
-----------   --------------------------------------------------------
${string^} Olá, Mundo! # Primeiro caractere para maiúsculo
${string^^} OLÁ, MUNDO! # Todos os caracteres para maiúsculas
${string,} Olá, Mundo! # Primeiro caractere para minúsculo
${string,,} Olá, mundo! # Todos os caracteres para letras minúsculas

O Bash 4.4 introduziu outro conjunto de expansões, que ele chama de transformação de parâmetro :

${string@Q} # Citação a ser reutilizada como entrada, como printf %q
${string@E} # Expandir combos de barra invertida, como printf %b
${string@P} # Expansão de string de prompt, usando as regras para PS1
${string@A} # Criação de instrução de atribuição, como declare -p, mas diferente
${string@a} # busca de atributos

Em ação:

$ string=$'bom "dia" não é?' ; echo "${string@Q}"
'bom "dia" não é?'

$ string='olá\tworld' ; echo "${string@E}"
Olá Mundo

$ string='\h:\w\$ ' ; echo "${string@P}"
lã:~$ 

$ string=olá; echo "${string@A}"
string='olá'
$ a=(uma matriz); echo "${a[@]@A}"
declare -aa=([0]="an" [1]="array")
$ declara -ri i=3 ; echo "${i@A}"
declare -ir i='3'

$ echo "${string@a}"

$ echo "${a@a}" "${i@a}"
ir

Expansão de parâmetros em arrays

Os arrays BASH são notavelmente flexíveis, porque estão bem integrados com as outras expansões do shell. Qualquer expansão de parâmetro que pode ser realizada em um elemento de array escalar ou individual pode igualmente aplicar-se a um array inteiro ou ao conjunto de parâmetros posicionais, de modo que todos os membros sejam expandidos de uma só vez, possivelmente com uma operação adicional mapeada em cada elemento. Isso é feito expandindo os parâmetros da forma @ , * , arrayname[@] e arrayname[*] . É fundamental que essas expansões especiais sejam citadas corretamente - quase sempre isso significa aspas duplas (por exemplo, "$@" ou "${cmd[@]}") - para que os membros sejam tratados literalmente como palavras individuais, independentemente de seu conteúdo. Por exemplo, arr=("${list[@]}" foo) trata corretamente todos os elementos na matriz de lista .

Primeiro as expansões:

$ a=(alpha beta gamma) # atribui ao nosso array base via atribuição composta
$ echo "${a[@]#a}" # corta 'a' do início de cada membro
alfa beta gama
$ echo "${a[@]%a}" # do final
alfa aposta gamm
$ echo "${a[@]//a/f}" # substituição
flphf betf gfmmf

As seguintes expansões (substituir no início ou no final) são muito úteis para a próxima parte:

$ echo "${a[@]/#a/f}" # substitui a por f no início
flpha beta gama
$ echo "${a[@]/%a/f}" # no final
alfaf betf gammf

Usamos estes para prefixar ou sufixo cada membro da lista:

$ echo "${a[@]/#/a}" # anexa a no início
aalpha abeta agamma # (obrigado a floyd-n-milan por isso)
$ echo "${a[@]/%/a}" # anexa um ao final
alfaa betaa gama

Isso funciona substituindo uma string vazia no início ou no final pelo valor que desejamos anexar.

Então, finalmente, um exemplo rápido de como você pode usar isso em um script, digamos, para adicionar um prefixo definido pelo usuário a cada destino:

$ PFX=inc_
$ a=("${a[@]/#/$PFX}")
$ echo "${a[@]}"
inc_alpha inc_beta inc_gamma

Isso é muito útil, como você pode imaginar, pois economiza loops em todos os membros do array.

O parâmetro especial @ também pode ser usado como array para fins de expansão de parâmetros:

${@:(-2):1} # penúltimo parâmetro
${@: -2:1} # sintaxe alternativa

Você não pode usar ${@:-2:1} (observe o espaço em branco), no entanto, porque isso entra em conflito com a sintaxe descrita na próxima seção.

Portabilidade

O shell Bourne original (7ª edição Unix) suporta apenas um conjunto muito limitado de opções de expansão de parâmetros:

${var-word} # se var estiver definido, use var; caso contrário, "palavra"
${var+word} # se var estiver definido, use "palavra"; caso contrário, nada
${var=word} # se var estiver definido, use var; caso contrário, use "palavra" E ...
                        # também atribui "palavra" a var
${var?error} # se var estiver definido, use var; caso contrário, imprima "erro" e saia

Estas são as únicas expansões completamente portáteis disponíveis.

Os shells POSIX (assim como KornShell e BASH ) oferecem isso, além de uma pequena variante:

${var:-word} # se var estiver definido E NÃO VAZIO, use var; caso contrário, "palavra"
da mesma forma para ${var:+word} etc.

POSIX, Korn (todas as versões) e Bash suportam as expansões ${var#word} , ${var%word} , ${var##word} e ${var%%word} .

ksh88 não suporta ${var/replace/with} ou ${var//replace/all} , mas ksh93 e Bash sim.

ksh88 não suporta expansão sofisticada com arrays (por exemplo, ${a[@]%.gif} ), mas ksh93 e Bash sim.

ksh88 não suporta o estilo arr=(...) de atribuição composta. Use set -A arrayname -- elem1 elem2 ... ou atribua cada elemento individualmente com arr[0]=val1 arr[1]=val2 ...


fonte:http://mywiki.wooledge.org/BashFAQ/073

Comentários



Faça o login para enviar uma mensagem