
Basicamente, eu tenho um conjunto de diretórios que são constantemente preenchidos com .rar e preciso ser capaz de extraí-los no local com exclusão automática dos arquivos .(rar|rXX) restantes. Como eu faria isso?
Nota: não posso excluir todos eles depois de concluído, eles devem ser excluídos conforme o script completa um conjunto rar.
Exemplo de estrutura de diretório:
/
/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
Responder1
Variante para 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
Os arquivos RAR também podem ser nomeados "legalmente", por exemplo, myarchive.part001.rar
e assim por diante, e isso teria que ser tratado separadamente de alguma forma se esses tipos de arquivos existirem. Uma forma pragmática de resolver isto é substituir
unrar e -- "${file}" && rm -- @(${file}|${file%.rar}.r[[:digit:]][[:digit:]])
com
unrar e -o- -- "${file}"
if [ $? -eq 0 -o $? -eq 10 ]; then
rm -- @(${file}|${file%.rar}.r[[:digit:]][[:digit:]])
fi
mas tenha cuidado, pois isso limpará os arquivos RAR mesmo se o código de erro 10 ("Nenhum arquivo para extrair") for fornecido e, portanto, geralmente não é recomendado em sua forma não modificada.
Resumindo, pode ser melhor simplesmente armazenar o material no formato arquivado e, em vez disso, usar a descompressão instantânea ou algo semelhante quando quiser usá-lo. Pode haver outros benefícios em manter o formato arquivado.
Responder2
Estou escrevendo isso de cabeça, então é um código não testado, mas deve colocar você no caminho certo. Basicamente, ele percorre a árvore para a qual você aponta, procurando por arquivos .rar. Ao encontrar um, ele irá descompactá-lo e excluir o arquivo original, a menos que unrar retorne diferente de zero. Ao acessar uma pasta, a função apenas chamará a si mesma, tornando-a 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"
O nome da função é completamente arbitrário. Gosto que eles sejam lidos como um inglês adequado quando invocados com seus argumentos. [[ -d /path ]]
retorna verdadeiro se o caminho existir e for um diretório. -f
faz o correspondente para arquivos. [[ "string" =~ "pattern"]]
é um bashismo que permite a correspondência de padrões em strings. Funciona principalmente como padrões glob.
A linha local x=pwd f
pode ser enigmática, mas apenas define duas variáveis locais: uma chamada x, para conter o pwd
, e outra chamada f, não inicializada (é inicializada no loop for abaixo, acabei de declará-la aqui para que seja local).
Armazenar pwd
e retornar a ele se sua função usar cd
é uma coisa boa (tm).
Observe que usar a saída de ls
programaticamente é geralmente Bad Mojo, e você deve evitá-lo como uma praga, em favor de find
.Se algum dos seus nomes de arquivo contiver um espaço, usar ls no seu script irá estragar tudo.Você foi avisado.
ZSH
Não tenho certeza se você pode fazer a mesma coisa no Bash, mas no ZSH, eu colocaria o seguinte em algum lugar.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
}
E então basta chamá-lo de dentro da pasta correspondente.