Il existe différents points d'échec possibles dans votre script. Tout d'abord, rm *.old*
utilisera le globbing pour créer une liste de tous les fichiers correspondants, et qui peut traiter les noms de fichiers contenant des espaces. Votre script, cependant, attribue une variable à chaque résultat du glob et le fait sans citer. Cela se cassera si vos noms de fichiers contiennent des espaces. Par exemple:
$ ls
'file name with spaces.old.txt' file.old.txt
$ rm *.old.* ## works: both files are deleted
$ touch "file.old.txt" "file name with spaces.old.txt"
$ for i in ./*; do oldfile=$i; rm -v $oldfile; done
rm: cannot remove './file': No such file or directory
rm: cannot remove 'name': No such file or directory
rm: cannot remove 'with': No such file or directory
rm: cannot remove 'spaces.old.txt': No such file or directory
removed './file.old.txt'
Comme vous pouvez le voir, la boucle a échoué pour le fichier avec des espaces dans son nom. Pour le faire correctement, vous devez citer la variable:
$ for i in ./*; do oldfile="$i"; rm -v "$oldfile"; done
removed './file name with spaces.old.txt'
removed './file.old.txt'
Le même problème s'applique à presque toutes les utilisations de $i
votre script. Vous devez toujours citer vos variables .
Le prochain problème possible est que vous semblez vous attendre à ce que les *.old.*
fichiers correspondent à l'extension .old
. Ce n'est pas le cas. Il correspond à "0 ou plusieurs caractères" ( *
), puis à a .
, puis à "old", puis à un autre .
puis à "0 ou plusieurs caractères à nouveau". Cela signifie qu'il ne correspondra pas à quelque chose comme file.old
, mais seulement à quelque chose comme `file.old.foo:
$ ls
file.old file.old.foo
$ for i in *; do if [[ "$i" == *.old.* ]]; then echo $i; fi; done
file.old.foo
Donc, pas d'ennemi de match file.old
. Dans tous les cas, votre script est beaucoup plus complexe que nécessaire. Essayez plutôt celui-ci:
#!/bin/bash
for i in *; do
if [[ -f "$i" ]]; then
if [[ "$i" == *.old ]]; then
rm -v "$i" || echo "rm failed for $i"
else
echo "$i doesn't have an .old extension"
fi
cp -v "$i" "$i".old
else
echo "$i is not a file"
fi
done
Notez que j'ai ajouté -v
aux instructions rm
et cp which does the same thing as what you were doing with your
echo`.
Ce n'est pas parfait car lorsque vous trouvez, par exemple, file.old
cela sera supprimé et, plus tard, le script essaiera de le copier et échouera car le fichier n'existe plus. Cependant, vous n'avez pas expliqué ce que votre script tente réellement de faire, donc je ne peux pas résoudre ce problème pour vous à moins que vous ne nous disiez ce que vous essayez vraiment d'accomplir.
Si vous voulez i) supprimer tous les fichiers avec l' .old
extension et ii) ajouter l' .old
extension à tous les fichiers existants qui ne l'ont pas, tout ce dont vous avez vraiment besoin est:
#!/bin/bash
for i in *.old; do
if [[ -f "$i" ]]; then
rm -v "$i" || echo "rm failed for $i"
else
echo "$i is not a file"
fi
done
## All the ,old files have been removed at this point
## copy the rest
for i in *; do
if [[ -f "$i" ]]; then
## the -v makes cp report copied files
cp -v "$i" "$i".old
fi
done
rm *.old.*
qui supprime ces fichiers mais pas le fichier de sauvegarde file.old. J'essaie de le faire dans mon script. MerciLes seuls cas
rm $oldfile
pourraient échouer sont lorsque votre nom de fichier contient un caractère deIFS
(espace, tabulation, saut de ligne) ou tout caractère glob (*
,?
,[]
).Si un caractère de
IFS
est présent, le shell effectuera la division des mots et en fonction de la présence de l'extension des noms de chemin des caractères globbing sur l'expansion variable.Ainsi, par exemple, si le nom du fichier est
foo bar.old.
, la variableoldfile
contiendrafoo bar.old.
.Quand vous faites:
shell divise d'abord l'expansion de l'
oldfile
espace en deux mots,foo
etbar.old.
. La commande devient donc:ce qui conduirait évidemment à un résultat inattendu. Soit dit en passant, si vous avez des opérateurs jokers (
*
,?
,[]
) dans l'expansion, puis l' expansion chemin serait fait aussi.Vous devez citer les variables pour obtenir le résultat souhaité:
Maintenant, aucun fractionnement de mot ou expansion de nom de chemin ne serait effectué, vous devriez donc obtenir le résultat souhaité, c'est-à-dire que le fichier souhaité serait supprimé. Si un nom de fichier commence par
-
, alors:Vous pourriez vous demander pourquoi nous n'avons pas besoin de citer des variables lorsqu'elles sont utilisées à l'intérieur
[[
, la raison en[[
est unbash
mot-clé et il gère l'expansion des variables en interne en conservant le littéral de l'expansion.Maintenant, quelques points:
Vous devez rediriger STDERR (
exec 2>errorfile
) avant larm
commande sinon le[[ -s errorfile ]]
test donnerait des faux positifsVous avez utilisé
[ -s $errorfile ]
, vous utilisez une extension de variable$errorfile
, qui serait NUL étant donné que laerrorfile
variable n'est définie nulle part. Peut-être que vous vouliez dire, simplement[ -s errorfile ]
, basé sur la redirection STDERRSi la variable
errorfile
est définie, lors de l'utilisation[ -s $errorfile ]
, elle étoufferait à nouveau les cas mentionnés ci-dessusIFS
et la globalisation car contrairement à[[
, elle[
n'est pas gérée en interne parbash
Dans la dernière partie du script, vous essayez
cp
le fichier déjà supprimé (encore une fois sans citer la variable), cela n'a aucun sens, vous devez vérifier ce mandrin et apporter les corrections nécessaires en fonction de votre cible.la source