
Básicamente, tengo un conjunto de directorios que se llenan constantemente con archivos .rar y necesito poder extraerlos en su lugar con la eliminación automática de los archivos .(rar|rXX) sobrantes. ¿Cómo haría esto?
Nota: No puedo eliminarlos todos una vez hecho, deben eliminarse cuando el script completa un conjunto rar.
Ejemplo de estructura de directorio:
/
/folder1/
/file1.rar
/file1.r00
/file1.r01
/folder2/
/sub.folder1/
/file2.part001.rar (contains a directory "file2")
/file2.part002.rar
/file2.part003.rar
/sub.folder2/
/file3.rar
/file3.r00
/file3.r01
Resultado Esperado:
/
/folder1/
/file1.ext
/folder2/
/sub.folder1/
/file2/
/file2.ext
/sub.folder2/
/file3.ext
Respuesta1
Variante de Bash:
#!/bin/bash
if [ ! -d "${1}" ]; then
printf '%s: error: mandatory argument is not a valid directory.' "${0##*/}" 1>&2
exit 1
fi
shopt -s extglob
for i in "${1}"/**/*.rar; do
cd -- "${i%/*}"
file=${i##*/}
unrar e -- "${file}" && rm -- @(${file}|${file%.rar}.r[[:digit:]][[:digit:]])
cd - >/dev/null
done
Los archivos RAR también pueden denominarse "legalmente", por ejemplo, myarchive.part001.rar
etc., y eso tendría que manejarse por separado de alguna manera si ese tipo de archivos existen. Una forma pragmática de resolver esto es reemplazar
unrar e -- "${file}" && rm -- @(${file}|${file%.rar}.r[[:digit:]][[:digit:]])
con
unrar e -o- -- "${file}"
if [ $? -eq 0 -o $? -eq 10 ]; then
rm -- @(${file}|${file%.rar}.r[[:digit:]][[:digit:]])
fi
pero tenga cuidado porque esto limpiará los archivos RAR incluso si se proporciona el código de error 10 ("No hay archivos para extraer") y, por lo tanto, generalmente no se recomienda en su forma no modificada.
Con todo, podría ser mejor simplemente tener el material almacenado en formato archivado y en su lugar utilizar la descompresión sobre la marcha o algo similar cuando desee utilizarlo. Puede haber otros beneficios al mantener el formato archivado.
Respuesta2
Estoy escribiendo esto fuera de mi cabeza, por lo que es un código no probado, pero debería llevarlo por el camino correcto. Básicamente, recorre el árbol al que apunta en busca de archivos .rar. Al encontrar uno, lo descomprimirá en su lugar y eliminará el archivo original a menos que unrar devuelva un valor distinto de cero. Al acceder a una carpeta, la función simplemente se llamará a sí misma, lo que hará que sea recursiva.
#!/bin/bash
[[ ! -d "$1" ]] && echo "Please point me at a directory!" && exit 1
function recursively_extract_all_rars_in() {
local x=`pwd` f
cd "$1"
for f in (*); do
[[ -d "$f" ]] && recursively_extract_all_rars_in "$f"
[[ -f "$f" ]] && [[ "$f" =~ "*.rar" ]] && unrar e "$f" && rm ${f%%.*}.r??
done
cd "$x"
}
recursively_extract_all_rars_in "$1"
El nombre de la función es completamente arbitrario. Me gusta que se lean como en inglés adecuado cuando se los invoca con sus argumentos. [[ -d /path ]]
devuelve verdadero si la ruta existe y es un directorio. -f
hace lo correspondiente para los archivos. [[ "string" =~ "pattern"]]
es un bashismo que permite la coincidencia de patrones en cadenas. Funciona principalmente como patrones globales.
La línea local x=pwd f
puede ser críptica, pero solo define dos variables locales: una llamada x, para contener el pwd
, y otra llamada f, no inicializada (se inicializa en el bucle for siguiente, simplemente la declaro aquí para que sea local).
Almacenar pwd
y volver a él si su función lo utiliza cd
es algo bueno (tm).
Tenga en cuenta que usar la salida de ls
programáticamente generalmente es Bad Mojo, y debe evitarlo como una plaga, a favor de find
.Si alguno de los nombres de sus archivos contiene un espacio, usar ls en su script será un gran error.Usted ha sido advertido.
ZSH
No estoy seguro de que puedas hacer lo mismo en Bash, pero en ZSH, pondría lo siguiente en algún lugar de.zshrc
function recursive_unrar() {
for f in **/*.rar; do
local cwd=`pwd` fbn=${f##*/}
cd "${f%/*}"
unrar e "$fbn"
rm "${fbn%%.*}.r{01..99} $fbn"
cd "$cwd"
done
}
Y luego simplemente llámalo desde dentro de la carpeta correspondiente.