web-dev-qa-db-fra.com

Globalisation basique qui correspond à tous les fichiers sauf ceux avec une extension spécifique, qui fonctionne sur les noms de fichiers qui incluent des caractères point

Je fais des trucs avec des fichiers audio, la plupart mais pas tous des fichiers mp3. Maintenant, je veux exécuter certaines commandes uniquement sur les fichiers qui ne sont pas des fichiers mp3, ou uniquement ceux qui n'ont pas de .mp3 extension.

Je me considère assez bon pour les expressions régulières, mais pas tant pour la globalisation de fichiers, qui est subtilement différente de manière inattendue.

J'ai regardé autour de moi et j'ai appris des autres SO & SE répond que Bash a "étendu le globbing" qui me permet de faire ceci:

file ../foo/bar/*.!(mp3)

Mais certains de mes noms de fichiers contiennent des points en plus de celui formant l'extension du nom de fichier:

../foo/bar/Naked_Scientists_Show_19.10.15.mp3
../foo/bar/YWCS_ep504-111519-pt1_5ej4_41cc9320.mp3_42827d48daefaa81ec09202e67fa8461_24419113.mp3
../foo/bar/eLife_Podcast_19.09.26.mp3
../foo/bar/gdn.sci.080428.bg.science_weekly.mp3

Il semble que le glob corresponde à partir du premier point, plutôt qu'à partir du dernier point. J'ai regardé la documentation mais il semble qu'ils soient beaucoup moins puissants que les regex. Mais je n'ai pas vraiment tout gâché car je ne passe pas beaucoup de temps sur les shells * nix.

Ai-je raté un moyen de pouvoir encore le faire avec la globalisation Bash? Sinon, un moyen de réaliser la même chose avec find ou un autre outil vaut toujours la peine d'être connu.

10
hippietrail

*.!(mp3) correspond à foo.bar.mp3 car c'est foo. suivi de bar.mp3 qui est qui n'est pas mp3.

Vous voulez !(*.mp3) ici, qui correspond à tout ce qui ne se termine pas par .mp3.

Si vous souhaitez faire correspondre des fichiers dont le nom contient au moins un . (Autre qu'un premier qui en ferait un fichier masqué) mais ne se termine pas par .mp3, Vous pouvez faire !(*.mp3|!(*.*)).

18
Stéphane Chazelas

Il y a aussi la variable GLOBIGNORE :

La variable GLOBIGNORE Shell peut être utilisée pour restreindre l'ensemble de noms de fichiers correspondant à un modèle. Si GLOBIGNORE est défini, chaque nom de fichier correspondant qui correspond également à l'un des modèles de GLOBIGNORE est supprimé de la liste des correspondances. Si l'option nocaseglob est définie, la correspondance avec les modèles dans GLOBIGNORE est effectuée sans tenir compte de la casse. Les noms de fichiers . et .. sont toujours ignorés lorsque GLOBIGNORE est défini et non null. Cependant, la définition de GLOBIGNORE sur une valeur non nulle a pour effet d'activer l'option dotglob Shell, donc tous les autres noms de fichiers commençant par ". ’Correspondra. Pour obtenir l'ancien comportement consistant à ignorer les noms de fichiers commençant par ".', faire '.* ’L'un des modèles de GLOBIGNORE. L'option dotglob est désactivée lorsque GLOBIGNORE n'est pas définie.

$ touch a.b.mp3 .c.mp3 foo.tgz .bar
$ echo *
a.b.mp3 foo.tgz
$ shopt -s extglob; echo *.!(mp3)
a.b.mp3 foo.tgz
$ GLOBIGNORE='*.mp3'; echo *
.bar foo.tgz
6
muru

la façon la plus simple à laquelle je peux penser:

find ${path-to-folder} -type f  | grep -vE ".*\.mp3$"

Vous trouvez tous les fichiers dans un dossier et le redirigez vers une grep étendue inversée:

Trouver tous les fichiers dans un emplacement

find ${path-to-folder} -type f 

Inverser grep et utiliser une expression régulière pour filtrer par extension

grep -vE ".*\.mp3$"

Drapeaux Grep:

  • -v grep inverse

  • -E grep étendu (utilisation de l'expression régulière)

Regex a expliqué:

  • .* signifie de 0 à n'importe quel nombre de caractères, tout caractère possible

  • \. recherche le point réel

  • mp3 pour la chaîne qui forme l'extension

  • $ signifie EOL

2
Kramer

Peut-être pas idéal pour votre situation, mais je me demandais comment créer une fonction en pur Bash puis passer l'extension en argument, ce qui peut être pratique si vous voulez l'ajouter dans votre bashrc et vous voulez faire la même chose à l'avenir, comme ce qui suit

Donc, fondamentalement, ce que nous faisons est le contrôle regex de votre extension souhaitée.

for file in *; do
  if [[ $file =~ \.mp3$ ]]; then
    echo $file
  fi
done

L'implémenter dans une fonction: Cela produirait tous les fichiers avec une extension spécifique dans votre répertoire actuel.

getFileByExt(){
local extension="$1"
if (( $# == 1 )); then
for file in *; do
  if [[ $file =~ \.$extension$ ]]; then
    echo $file
  fi
done
else
  echo "Usage: ${FUNCNAME[0]} <extension>" 
## If run from bashrc, return the name of function
fi
}

Maintenant, par exemple pour obtenir tous les fichiers avec mp3 extension, ce serait aussi simple que de faire:

getFileByExt mp3

Et pour obtenir des fichiers sans extension spécifique: Cela produirait tous les fichiers qui n'ont pas d'extension spécifique dans votre répertoire actuel.

getFileWithoutExt(){
local extension="$1"
if (( $# == 1 )); then
for file in *; do
  if [[ ! $file =~ \.$extension$ ]]; then
    echo $file
  fi
done
else
  echo "Usage: ${FUNCNAME[0]} <extension>"
fi
}

De même pour obtenir des fichiers sans mp3 l'extension suffit simplement:

getFileWithoutExt mp3

Pour plus d'informations:

https://stackoverflow.com/questions/407184/how-to-check-the-extension-of-a-filename-in-a-bash-script

https://stackoverflow.com/questions/18278990/easiest-way-to-check-for-file-extension-in-bash/1828035

1
Rakib Fiha