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 $i
su 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é -v
a las declaraciones rm
y cp which does the same thing as what you were doing with your
echo`.
Esto no es perfecto ya que cuando encuentre, por ejemplo, file.old
que 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 .old
extensión y ii) agregar la .old
extensió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 $oldfile
podrí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
IFS
presente, 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 variableoldfile
contendríafoo bar.old.
.Cuando tu lo hagas:
Shell al principio divide la expansión del
oldfile
espacio en dos palabras,foo
ybar.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 unabash
palabra 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 delrm
comando; 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 laerrorfile
variable no está definida en ninguna parte. Quizás quisiste decir, simplemente[ -s errorfile ]
, basado en la redirección STDERRSi
errorfile
se define la variable , durante el uso[ -s $errorfile ]
, volvería a ahogarse en los casos mencionados anteriormenteIFS
y se bloqueará porque[[
, a diferencia ,[
no se maneja internamente porbash
En la parte posterior de la secuencia de comandos, está intentando
cp
el 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