Je voudrais dire si une chaîne $string
correspondrait à un modèle glob $pattern
. $string
peut ou peut ne pas être le nom d'un fichier existant. Comment puis-je faire ceci?
Supposons les formats suivants pour mes chaînes d'entrée:
string="/foo/bar"
pattern1="/foo/*"
pattern2="/foo/{bar,baz}"
Je voudrais trouver un idiome bash qui détermine si $string
serait compensée par $pattern1
, $pattern2
ou tout autre motif glob arbitraire. Voici ce que j'ai essayé jusqu'à présent:
[[ "$string" = $pattern ]]
Cela fonctionne presque, sauf qu'il
$pattern
est interprété comme un modèle de chaîne et non comme un modèle global.[ "$string" = $pattern ]
Le problème avec cette approche est qu'elle
$pattern
est étendue et que la comparaison des chaînes est effectuée entre$string
et l'expansion de$pattern
.[[ "$(find $pattern -print0 -maxdepth 0 2>/dev/null)" =~ "$string" ]]
Celui-ci fonctionne, mais uniquement s'il
$string
contient un fichier qui existe.[[ $string =~ $pattern ]]
Cela ne fonctionne pas car l'
=~
opérateur fait$pattern
en sorte qu'il soit interprété comme une expression régulière étendue et non comme un modèle glob ou générique.
{bar,baz}
n'est pas un modèle. C'est l'expansion des paramètres. Une différence subtile mais critique en cela{bar,baz}
est développée très tôt dans de multiples arguments,bar
etbaz
.ls /foo/*
maintenant vous pouvez égaler dans unfoo/{bar,baz}
s'agit en fait d'une extension d'accolade (pas d'une extension de paramètre) alors quefoo/*
c'est une extension de nom de chemin.$string
est l'expansion des paramètres. Tout cela se fait à différents moments et par différents mécanismes.case
instruction exécute l'extension de nom de chemin ("globbing") conformément au manuel de Bash.Réponses:
Il n'y a pas de solution générale à ce problème. La raison en est que, dans bash, l'expansion d'accolade (c'est-à-dire,
{pattern1,pattern2,...}
et l'expansion de nom de fichier (alias les modèles glob)) sont considérées comme des choses distinctes et développées dans différentes conditions et à différents moments. Voici la liste complète des extensions que bash effectue:Étant donné que nous ne nous soucions que d'un sous-ensemble de ces derniers (peut-être l'expansion d'accolade, de tilde et de chemin d'accès), il est possible d'utiliser certains modèles et mécanismes pour restreindre l'expansion de manière contrôlable. Par exemple:
L'exécution de ce script génère la sortie suivante:
Cela fonctionne car
set -f
désactive l'expansion des noms de chemin, donc seules l'expansion entre accolades et l'expansion tilde se produisent dans l'instructionfor pattern in /foo/{*,foo*,bar*,**,**/*}
. Nous pouvons ensuite utiliser l'opération[[ $string == $pattern ]]
de test pour tester l'expansion du nom de chemin une fois que l'extension d'accolade a déjà été effectuée.la source
Je ne crois pas que ce
{bar,baz}
soit un modèle de glob de shell (bien que ce soit certainement le cas/foo/ba[rz]
) mais si vous voulez savoir si des$string
correspondances$pattern
vous pouvez le faire:Vous pouvez en faire autant que vous le souhaitez:
la source
{bar,baz}
n'est pas un modèle global. J'ai déjà trouvé une solution à ma question qui en tient compte.Comme Patrick l'a souligné, vous avez besoin d'un "type différent" de motif:
Les citations n'y sont pas nécessaires.
la source
sed
opération simple .J'utiliserais ainsi grep:
Ce qui donne la sortie:
la source
en zsh:
la source