Hay varios puntos de falla posibles en su secuencia de comandos. En primer lugar, rm *.old*usará globbing para crear una lista de todos los archivos coincidentes, y eso puede tratar con nombres de archivos que contienen espacios en blanco. Sin embargo, su script asigna una variable a cada resultado del glob y lo hace sin citar. Eso se romperá si los nombres de sus archivos contienen espacios en blanco. Por ejemplo:
$ 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'
Como puede ver, el bucle falló para el archivo con espacios en su nombre. Para hacerlo correctamente, deberá citar la variable:
$ for i in ./*; do oldfile="$i"; rm -v "$oldfile"; done
removed './file name with spaces.old.txt'
removed './file.old.txt'
El mismo problema se aplica a casi todos los usos de $isu secuencia de comandos. Usted debe siempre citar sus variables .
El siguiente problema posible es que parece esperar que *.old.*coincida con los archivos con la extensión .old. No lo hace. Coincide con "0 o más caracteres" ( *), luego a ., luego "viejo", luego otro .y luego "0 o más caracteres nuevamente". Esto significa que no coincidirá con algo como file.old, sino solo algo como `file.old.foo:
$ ls
file.old file.old.foo
$ for i in *; do if [[ "$i" == *.old.* ]]; then echo $i; fi; done
file.old.foo
Entonces, no hay rival para el enemigo file.old. En cualquier caso, su script es mucho más complejo de lo necesario. Prueba este en su lugar:
#!/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
Tenga en cuenta que agregué -va las declaraciones rmy cp which does the same thing as what you were doing with yourecho`.
Esto no es perfecto ya que cuando encuentre, por ejemplo, file.oldque se eliminará y, más adelante, el script intentará copiarlo y fallará ya que el archivo ya no existe. Sin embargo, no ha explicado lo que su script realmente está intentando hacer, así que no puedo arreglarlo por usted a menos que nos diga lo que realmente está tratando de lograr.
Si lo que desea es i) eliminar todos los archivos con la .oldextensión y ii) agregar la .oldextensión a cualquier archivo existente que no lo tenga, todo lo que realmente necesita es:
#!/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.*que elimina estos archivos pero no el archivo de respaldo file.old. Estoy tratando de hacer eso en mi guión. GraciasLos únicos casos
rm $oldfilepodrían fallar son cuando su nombre de archivo contiene ningún carácter deIFS(espacio, tabulación, nueva línea) o cualquier carácter glob (*,?,[]).Si hay algún carácter de
IFSpresente, el shell realizará la división de palabras y se basará en la presencia de expansión de nombres de ruta de caracteres globales en la expansión variable.Entonces, por ejemplo, si el nombre del archivo es
foo bar.old., la variableoldfilecontendríafoo bar.old..Cuando tu lo hagas:
Shell al principio divide la expansión del
oldfileespacio en dos palabras,fooybar.old.. Entonces el comando se convierte en:lo que obviamente conduciría a un resultado inesperado. Por cierto, si tiene alguna operadores englobamiento (
*,?,[]) en la expansión, a continuación, la expansión de ruta sería hecho también.Debe citar las variables para obtener el resultado deseado:
Ahora, no se realizaría la división de palabras ni la expansión del nombre de ruta, por lo tanto, debería obtener el resultado deseado, es decir, se eliminaría el archivo deseado. Si comienza algún nombre de archivo
-, entonces:Puede preguntar, por qué no necesitamos citar variables cuando se usa dentro
[[, la razón[[es que es unabashpalabra clave y maneja la expansión de variables internamente manteniendo la expansión literal.Ahora, un par de puntos:
Debe redirigir STDERR (
exec 2>errorfile) antes delrmcomando; de lo contrario, la[[ -s errorfile ]]prueba daría falsos positivosHa utilizado
[ -s $errorfile ], está utilizando una expansión variable$errorfile, que sería NUL dado que laerrorfilevariable no está definida en ninguna parte. Quizás quisiste decir, simplemente[ -s errorfile ], basado en la redirección STDERRSi
errorfilese define la variable , durante el uso[ -s $errorfile ], volvería a ahogarse en los casos mencionados anteriormenteIFSy se bloqueará porque[[, a diferencia ,[no se maneja internamente porbashEn la parte posterior de la secuencia de comandos, está intentando
cpel archivo ya eliminado (de nuevo sin citar la variable), esto no tiene ningún sentido, debe verificar ese mandril y hacer las correcciones necesarias en función de su objetivo.fuente