Classifique os arquivos de acordo com suas extensões

2

Eu fiz um script que irá ordenar os arquivos de acordo com sua extensão e colocá-los na pasta correta. Por exemplo, coloque abc.jpg no diretório jpg .

#!/bin/bash
#this script sorts files according to their extensions
oldIFS=$IFS
IFS=$'\n'
(find . -type f) > /tmp/temp
for var in 'cat /tmp/temp'
do
name='basename "$var"'
ext='echo $name | cut -d'.' -f2- | cut -d'.' -f2- | cut -d'.' -f2- | cut -d'.' -f2- | cut -d'.' -f2- | cut -d'.' -f2- | cut -d'.' -f2-'
mkdir -p $ext
mv "$var" $ext/ 2> /dev/null
done
IFS=$oldIFS

problema com este script:

  1. envolve o uso do IFS, diz-se que evita o uso do IFS, tanto quanto possível
  2. não classifica o arquivo sem extensões de arquivo
  3. ele classificará arquivos como abc.tar.bz na pasta chamada bz, mas, no entanto, esse arquivo deve estar na pasta tar.bz
  4. veja a linha 9 do meu script; se algum arquivo contiver mais não. de pontos (em seu nome) do que não. de cut -d'.' -f2- no script do que se resultasse no nome do arquivo obtido na parte de extensão.
    por exemplo, um arquivo chamado i.am.live.in.india.and.i.study.computer.science.txt será colocado na pasta chamada study.computer.science.txt

você também pode sugerir quaisquer ajustes para tornar esse script mais pequeno e organizado.

    
por Edward Torvalds 23.11.2014 / 22:33

2 respostas

1

Embora o problema geral de identificar extensões seja difícil, você pode limpar o script um pouco:

  1. Diga find para considerar apenas arquivos com uma extensão: -iname '*.*'
  2. Use awk em vez de cut você mesmo:
  3. Use um script e, em seguida, diga find para executar esse script.

Assim: um script chamado, digamos, move.sh :

#! /bin/bash
for i
do
    ext=/some/where/else/$(awk -F. '{print $NF}' <<<"$i")
    mkdir -p "$ext"
    mv "$i" "$ext"
done

Em seguida, execute find assim:

find . -name '*.*' -type f -exec move.sh {} +

Isso tem o problema que você não pode reorganizar dentro da pasta, então você pode usar xargs :

find . -name '*.*' -type f -print0 > /tmp/temp
xargs -0 move.sh < /tmp/tmp

Não tenho muita certeza da eficiência envolvida, mas outra abordagem seria obter todas as extensões e, em seguida, mover todos os arquivos envolvidos de uma só vez.

Algo como:

find . -name '*.*' -type f -print0 | sed -z 's/.*\.//g' | sort -zu > /tmp/file-exts

Isso deve fornecer uma lista de extensões de arquivo exclusivas. Então, nosso move.sh será parecido com:

#!/bin/bash
for i
do
    mkdir -p "$i"
    find . -name "*.$i" -type f -exec mv -t "$i" {} +
done

E nós vamos executá-lo:

xargs -0 move.sh < /tmp/file-exts

Eu faço algumas suposições neste post, como sed e sort support -z (permitindo que trabalhem com as linhas terminadas em NUL que find e xargs prosperam). / p>     

por 23.11.2014 / 22:56
3

Recursing em subdiretórios

A análise da saída de find não é confiável. E se houvesse um nome de arquivo com uma nova linha? Use find … -exec … , o que garante um processamento confiável.

find . -type f -exec sh -c '…' {} \;

O fragmento de shell recebe o nome do arquivo em $0 . Note que este é um processo shell separado, ele não herda variáveis ou funções do script grandparent. Você pode acelerar o processamento usando o mesmo subprocesso de shell para lidar com vários arquivos.

find . -type f -exec sh -c 'for x; do … done' _ {} +

Desta vez, dentro do loop, o nome do arquivo está na variável x .

Quebrando o nome do arquivo

Invocar utilitários externos, como sed , cut , etc., é frágil: você precisa ser extremamente cuidadoso para evitar o desconforto de alguns nomes de arquivos. Você não precisa disso: os recursos de processamento de strings integrados do shell são suficientes para o que você deseja fazer aqui. Dado um nome de arquivo $x :

directory=${x%/*}
basename=${x##*/}
extension=…
if [ -n "$extension" ]; then
  mkdir -p "$directory/extension"
  mv "$x" "$directory/extension"
fi

A extensão

Qual é a extensão de um arquivo? É a parte depois de um dos . nos nomes. Não há nenhum padrão que diga qual deles. Cabe a você decidir o que considera ser a extensão em casos como foo.tar.gz ou bar-1.2 .

Veja alguns códigos de exemplo que consideram extensões de compactação comuns para aninhar e que exigem extensões para conter uma letra, de modo que foo-1.2.tar.gz seja considerado como tendo a extensão tar.gz .

extension=
while case "${basename##*.}" in
        gz|bz2|xz) extension=.${basename##*.}$extension;; # stackable extension
        *) false;;
do
  basename=${basename%.*}
done
case "${basename##*.}" in
  "$basename") :;; # no . ==> no extension
  *[!0-9A-Za-z]*) :;; # only allow alphanumeric characters
  *[A-Za-z]*) extension=${basename##*.}$extension;; # non-stackable extension
  *) false;; # require at least one letter
esac
extension=${extension#.}
    
por 23.11.2014 / 23:00