Comment supprimer l’extension d’un fichier?

J’ai un dossier qui est plein de fichiers .bak et d’autres fichiers également. Je dois supprimer l’extension de tous les fichiers .bak dans ce dossier. Comment puis-je créer une commande qui acceptera un nom de dossier, puis supprimera l’extension de tous les fichiers .bak de ce dossier?

Merci.

Pour supprimer une chaîne à la fin d’une variable BASH, utilisez la syntaxe ${var%ending} . C’est l’une des nombreuses manipulations de chaînes disponibles dans BASH .

Utilisez-le comme ceci:

 # Run in the same directory as the files for FILENAME in *.bak; do mv "$FILENAME" "${FILENAME%.bak}"; done 

Cela fonctionne très bien en tant que one-liner, mais vous pouvez aussi l’envelopper comme un script pour travailler dans un répertoire arbitraire:

 # If we're passed a parameter, cd into that directory. Otherwise, do nothing. if [ -n "$1" ]; then cd "$1" fi for FILENAME in *.bak; do mv "$FILENAME" "${FILENAME%.bak}"; done 

Notez que si vous citez vos variables est presque toujours une bonne pratique, le fichier for FILENAME in *.bak est toujours dangereux si l’un de vos noms de fichiers peut contenir des espaces. Lisez la réponse de David W. pour une solution plus robuste, et ce document pour des solutions alternatives.

Il existe plusieurs manières de supprimer les suffixes de fichiers:

Dans BASH et Kornshell, vous pouvez utiliser le filtrage des variables d’environnement. Recherchez ${parameter%word} dans la page de manuel BASH pour obtenir des informations complètes. Fondamentalement, # est un filtre gauche et % est un filtre droit . Vous pouvez vous en souvenir car # est à gauche de % .

Si vous utilisez un double filtre (par exemple ## ou %% , vous essayez de filtrer la plus grande correspondance. Si vous avez un seul filtre (par exemple # ou % , vous essayez de filtrer la plus petite correspondance).

Les correspondances sont filtrées et vous obtenez le rest de la chaîne:

 file="this/is/my/file/name.txt" echo ${file#*/} #Matches is "this/` and will print out "is/my/file/name.txt" echo ${file##*/} #Matches "this/is/my/file/" and will print out "name.txt" echo ${file%/*} #Matches "/name.txt" and will print out "/this/is/my/file" echo ${file%%/*} #Matches "/is/my/file/name.txt" and will print out "this" 

Notez qu’il s’agit d’une correspondance de globes et non d’une expression régulière. Si vous souhaitez supprimer un suffixe de fichier:

 file_sans_ext=${file%.*} 

Le .* Correspondra à la période et à tous les caractères après. Comme il s’agit d’un % unique, il correspondra au plus petit glob du côté droit de la chaîne. Si le filtre ne correspond à rien, il est identique à votre chaîne d’origine.

Vous pouvez vérifier un suffixe de fichier avec quelque chose comme ceci:

 if [ "${file}" != "${file%.bak}" ] then echo "$file is a type '.bak' file" else echo "$file is not a type '.bak' file" fi 

Ou vous pourriez faire ceci:

 file_suffix=$(file##*.} echo "My file is a file '.$file_suffix'" 

Notez que cela supprimera la période de l’extension du fichier.

Ensuite, nous allons boucler:

 find . -name "*.bak" -print0 | while read -d $'\0' file do echo "mv '$file' '${file%.bak}'" done | tee find.out 

La commande find trouve les fichiers que vous spécifiez. -print0 sépare les noms des fichiers avec un symbole NUL – qui est l’un des rares caractères non autorisés dans un nom de fichier. Le -d $ \ 0 means that your input separators are NUL symbols. See how nicely the means that your input separators are NUL symbols. See how nicely the find -print0 and lisez -d $ ‘\ 0’` ensemble?

Vous ne devriez presque jamais utiliser le for file in $(*.bak) méthode for file in $(*.bak) . Cela échouera si les fichiers ont un espace blanc dans le nom.

Notez que cette commande ne déplace aucun fichier. Au lieu de cela, il produit un fichier find.out avec une liste de tous les find.out fichiers. Vous devriez toujours faire quelque chose comme ça quand vous faites des commandes qui fonctionnent sur des quantités massives de fichiers, juste pour être sûr que tout va bien.

Une fois que vous avez déterminé que toutes les commandes de find.out sont correctes, vous pouvez l’exécuter comme un script shell:

 $ bash find.out 

Avertissement: il n’y a pas de vérification d’erreur:

 #!/bin/bash cd "$1" for i in *.bak ; do mv -f "$i" "${i%%.bak}" ; done 

rename .bak '' *.bak

( rename dans le paquetage util-linux )

Vous pouvez toujours utiliser la commande find pour obtenir tous les sous-répertoires

 for FILENAME in `find . -name "*.bak"`; do mv --force "$FILENAME" "${FILENAME%.bak}"; done