Gostaria de dizer se uma string $string
seria correspondida por um padrão glob $pattern
. $string
pode ou não ser o nome de um arquivo existente. Como posso fazer isso?
Suponha os seguintes formatos para minhas seqüências de caracteres de entrada:
string="/foo/bar"
pattern1="/foo/*"
pattern2="/foo/{bar,baz}"
Eu gostaria de encontrar uma linguagem bash que determina se $string
seria acompanhado por $pattern1
, $pattern2
ou qualquer outro padrão glob arbitrária. Aqui está o que eu tentei até agora:
[[ "$string" = $pattern ]]
Isso quase funciona, exceto que
$pattern
é interpretado como um padrão de cadeia e não como um padrão glob.[ "$string" = $pattern ]
O problema com essa abordagem é que
$pattern
é expandido e a comparação de cadeias é executada entre$string
e a expansão de$pattern
.[[ "$(find $pattern -print0 -maxdepth 0 2>/dev/null)" =~ "$string" ]]
Este funciona, mas somente se
$string
contém um arquivo que existe.[[ $string =~ $pattern ]]
Isso não funciona porque o
=~
operador faz$pattern
com que seja interpretado como uma expressão regular estendida, não como um padrão glob ou curinga.
{bar,baz}
não é um padrão. É expansão de parâmetros. A diferença sutil, porém crítica,{bar,baz}
é expandida muito cedo em vários argumentos,bar
ebaz
.ls /foo/*
agora você pode combinar em umfoo/{bar,baz}
na verdade é uma expansão entre chaves (não uma expansão de parâmetro) enquantofoo/*
é uma expansão de nome de caminho.$string
é expansão de parâmetro. Tudo isso é feito em momentos diferentes e por mecanismos diferentes.case
instrução executa Expansão do nome do caminho ("globbing") conforme o manual do Bash.Respostas:
Não há solução geral para esse problema. O motivo é que, no bash, a expansão de chaves (ou seja,
{pattern1,pattern2,...}
expansão de nome de arquivo (também conhecida como padrões glob)) é considerada uma coisa separada e expandida sob diferentes condições e em diferentes momentos.Aqui está a lista completa das expansões executadas pelo bash:Como nos preocupamos apenas com um subconjunto deles (talvez expansão entre chaves, til e nome do caminho), é possível usar certos padrões e mecanismos para restringir a expansão de maneira controlável. Por exemplo:
A execução desse script gera a seguinte saída:
Isso funciona porque
set -f
a expansão desativa caminho, portanto, apenas a expansão cinta e expansão til ocorrer na declaraçãofor pattern in /foo/{*,foo*,bar*,**,**/*}
. Em seguida, podemos usar a operação[[ $string == $pattern ]]
de teste para testar a expansão do nome do caminho após a expansão da chave já ter sido executada.fonte
Eu não acredito que esse
{bar,baz}
seja um padrão shell glob (embora certamente/foo/ba[rz]
seja), mas se você quiser saber se$string
corresponde,$pattern
pode:Você pode fazer quantas quiser:
fonte
{bar,baz}
não é um padrão global. Eu já criei uma solução para minha pergunta que leva isso em consideração.Como Patrick apontou, você precisa de um "tipo diferente" de padrão:
Citações não são necessárias lá.
fonte
sed
operação simples .Eu usaria o grep assim:
O que fornece a saída:
fonte
no zsh:
fonte