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