O que% faz nas seqüências de caracteres do shell do Linux?


28

No shell do Linux, o que% faz, como em:

for file in *.png.jpg; do
  mv "$file" "${file%.png.jpg}.jpg"
done

4
Toda vez que procuro isso, geralmente encontro a seção correta da página de manual do bash pesquisando %%ou ##, pois isso é memorável e raro o suficiente para encontrar a seção correta rapidamente. man bash /##
Peter Cordes

3
@ PeterCordes Eu sempre me lembro disso: "É 5%, então% está no final e, portanto, corta do fim. E é o número 5, então # está no início e corta desde o início". Mas às vezes eu até confundo esse ...
glglgl 31/08/16

2
@glglgl: Em um teclado típico dos EUA, #fica imediatamente à esquerda $e %imediatamente à direita. Não é necessário mnemônico - basta olhar para baixo. (Isso é provavelmente pelo menos parte da razão pela qual foram escolhidos aqueles símbolos.)
Kevin J. perseguição

@ KevinJ.Chase Nem todo mundo no mundo tem um teclado típico dos EUA. Mas, de fato, em um teclado alemão,% também tem direito a $, isso poderia ser um começo para memorizar.
glglgl

Respostas:


29

Quando %é usado no padrão, ${variable%substring}ele retornará o conteúdo de variablecom a menor ocorrência de substringexcluídos da parte de trás variable.

Essa função suporta padrões curinga - é por isso que aceita estrela (asterisco) como um substituto para zero ou mais caracteres.

Deve-se mencionar que isso é específico do Bash - outros shells do linux não contêm necessariamente essa função.

Se você quiser aprender mais sobre manipulação de strings no Bash, sugiro que você leia esta página. Entre outras funções úteis, por exemplo - explica o que %%faz :)

Edit: Eu esqueci de mencionar que quando é usado em padrão $((variable%number))ou $((variable1%$variable2))o %personagem funcionará como operador de módulo. DavidPostill tem links de documentação mais específicos em sua resposta.

Quando %é usado em um contexto diferente, deve ser reconhecido apenas como caractere regular.


2
O operador suporta padrões curinga , não expressões regulares.
precisa saber é o seguinte

Como o gardenhead mencionado - ele suporta padrões globais, não expressões regulares. Na expressão regular, uma estrela significa zero ou mais caracteres anteriores.
Slebetman 31/08/16

5
O guia que você tiver vinculado a é muito não recomendada pela maioria dos usuários de câmbio Unix e Linux pilha . Eu recomendo o Guia Wooledge Bash .
Curinga

3
Os operadores de remoção de prefixo e sufixo são padrão , portanto devem ser utilizáveis ​​em qualquer shshell compatível, não apenas no Bash. (embora talvez não seja cshassim).
Ilkkachu

1
Outro contexto em que %é usado está nos especificadores de formato para printf.
Pausado até novo aviso.

9

Manual de Referência do Bash: Expansão dos parâmetros do shell

${parameter%word}
${parameter%%word}

A palavra é expandida para produzir um padrão, assim como na expansão do nome do arquivo. Se o padrão corresponder a uma parte à direita do valor expandido do parâmetro , o resultado da expansão será o valor 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. Se parâmetro for ‘@’ou ‘*’,a operação de remoção de padrão for aplicada a cada parâmetro posicional, por sua vez, e a expansão for a lista resultante. Se parâmetro é uma variável de matriz inscrita com ‘@’ ou‘*’, a operação de remoção de padrão é aplicada a cada membro da matriz, por sua vez, e a expansão é a lista resultante.


2
Nota: algumas expansões de parâmetros, incluindo%, são recursos posix que muitos shells suportam.
Kojiro # 30/16

7

Ao experimentar, acho que uma correspondência após% é descartada, quando a cadeia é colocada entre colchetes (chaves).

Ilustrar:

touch abcd         # Create file abcd

for file in ab*; do
 echo $file        # echoes the filename
 echo $file%       # echoes the filename plus "%"
 echo ${file%}     # echoes the filename
 echo "${file%}"   # echoes the filename
 echo
 echo "${file%c*}" # Discard anything after % matching c*
 echo "${file%*}"  # * is not greedy
 echo ${file%c*}   # Without quotes works too
 echo "${file%c}"  # No match after %, no effect
 echo $file%c*     # Without {} fails
done

Aqui está a saída:

abcd
abcd%
abcd
abcd

ab
abcd
ab
abcd
abcd%c*

7

No shell do Linux ( bash), o que %faz?

for file in *.png.jpg; do
  mv "$file" "${file%.png.jpg}.jpg"
done

Nesse caso em particular, o operador %é de correspondência de padrões (observe que também pode ser um operador de módulo ).


Operador de correspondência de padrões

$ {var% $ Pattern}, $ {var %% $ Pattern}

${var%$Pattern}Remova da $varparte mais curta $Patternque corresponde ao back-end de $var.

${var%%$Pattern}Remova da $varparte mais longa $Patternque corresponde ao back-end de $var.

Exemplo: Correspondência de Padrão na Substituição de Parâmetro

#!/bin/bash
# patt-matching.sh

# Pattern matching  using the # ## % %% parameter substitution operators.

var1=abcd12345abc6789
pattern1=a*c  # * (wild card) matches everything between a - c.

echo
echo "var1 = $var1"           # abcd12345abc6789
echo "var1 = ${var1}"         # abcd12345abc6789
                              # (alternate form)
echo "Number of characters in ${var1} = ${#var1}"
echo

echo "pattern1 = $pattern1"   # a*c  (everything between 'a' and 'c')
echo "--------------"
echo '${var1#$pattern1}  =' "${var1#$pattern1}"    #         d12345abc6789
# Shortest possible match, strips out first 3 characters  abcd12345abc6789
#                                     ^^^^^               |-|
echo '${var1##$pattern1} =' "${var1##$pattern1}"   #                  6789      
# Longest possible match, strips out first 12 characters  abcd12345abc6789
#                                    ^^^^^                |----------|

echo; echo; echo

pattern2=b*9            # everything between 'b' and '9'
echo "var1 = $var1"     # Still  abcd12345abc6789
echo
echo "pattern2 = $pattern2"
echo "--------------"
echo '${var1%pattern2}  =' "${var1%$pattern2}"     #     abcd12345a
# Shortest possible match, strips out last 6 characters  abcd12345abc6789
#                                     ^^^^                         |----|
echo '${var1%%pattern2} =' "${var1%%$pattern2}"    #     a
# Longest possible match, strips out last 12 characters  abcd12345abc6789
#                                    ^^^^                 |-------------|

# Remember, # and ## work from the left end (beginning) of string,
#           % and %% work from the right end.

echo

exit 0

Substituição do parâmetro de origem


Operador de módulo

%

modulo ou mod (retorna o restante de uma operação de divisão inteira)

bash$ expr 5 % 3
2

5/3 = 1, com o restante 2

Operadores de origem


Talvez eu tenha entendido: isso é para coisas como .*e %define que não é ganancioso, enquanto o %%torna ganancioso? Então, na verdade, no exemplo de renomeação, não importa se é para usar %ou %%se mv "$file" "${file%.*png.jpg}.jpg"(observe o *) usando %% renomeia todos os arquivos para apenas .jpg, certo?
Thomas Weller

@ThomasWeller Acho que está correto. Mas eu não sou especialista em festança.
DavidPostill

Dizer "Remover ... a parte mais curta de $Pattern" está errado, pois a variável $Patternnão está definida no exemplo, apenas o texto "Padrão" está sendo removido $varao fazer ${var%Pattern}ou ${var%%Pattern}. Talvez seja apenas um erro de digitação, mas é mais um exemplo de tldp.org estar errado. BashGuide ou Bash Hackers Wiki são referências muito melhores no imho.
John B #

@JohnB Thanks. Ambos os links foram marcados como favoritos. Corrigi o texto na resposta.
DavidPostill
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.