Exclusão de arquivos sob condições especiais, recursivamente, se possível

3

Eu estou procurando por uma seqüência de comando unix, que é capaz de executar uma ação de exclusão condicional bastante complexa.

Todos os arquivos com as extensões "[NAME] .cut" e "[NAME] .cut.bak" serão excluídos, SE não houver nenhum arquivo correspondente chamado "[NAME] .rec" ou "[NAME] .mpg "na mesma pasta.

O comando deve ser executado em um dispositivo integrado com um kernel mínimo e, portanto, não usar "ferramentas especiais". por exemplo. 'ls' e 'rm' podem ser usados, 'find' não está presente (isto é, somente através de uma ferramenta externa, da qual eu preferiria não depender)

Se possível, o comando deve apagar recursivamente em subdiretórios também ...

O plano de fundo é o seguinte: Estou desenvolvendo uma ferramenta para um PVR baseado em Linux, que permite o corte de programas gravados. Para cada gravação (extensão .rec ou .mpg), os marcadores de segmento são armazenados em um arquivo .cut. Quando alguma gravação é movida / renomeada / excluída, o arquivo de corte correspondente permanece no disco inútil. Eu já implementei a remoção desses arquivos cortados inúteis em C. Mas eu estou pensando, se pode haver uma solução baseada em um sistema (simples). Neste caso, poderia ser executado via 'system' e & em segundo plano, o que tornaria meu aplicativo mais responsivo ...

Aqui estão os comandos, que estão incluídos no firmware do PVR:

afinidade, arp, awk, nome base, bash, busybox, gato, chgrp, chmod, chown, cmp, cp, cramfsck, corte, data, dd, df, nome do diretório, dmesg, du, echo, egrep, env, expr , falso, fgrep, flash_erase, flash_eraseall, flash_info, livre, getty, grep, cabeçalho, hexdump, hostname, id, ifconfig, instalar, kill, killall, ln, logger, login, ls, md5sum, mkcramfs, mkdir, mknod, mktemp mais, monte, mv, bom, norcleanmark, od, passwd, pidof, ping, pmtest, portmap, printenv, printf, ps, pwd, readlink, renice, rm, rmdir, rota, sed, seq, sh, desligamento, sono , tipo, cordas, stty, sync, cauda, tee, telnet, tftp, tempo, tinylogin, toque, tr, true, tty, gêmeo, umount, uname, uniq, usleep, vi, wc, que, whoami, xargs, sim

Você tem alguma dica para mim?

    
por chris86 28.06.2015 / 14:05

2 respostas

4

Eu não consegui manter isso mais simples; isso funciona, mas assume que não há arquivos cujo nome de arquivo contenha novas linhas no diretório de destino ; primeiro teste o comando usando isto:

find . -type f \( -name "*.cut" -o -name "*.cut.bak" \) -exec bash -c '[ -f "$(<<< "{}" sed "s/\(.*\/[^.]*\).*//").rec" -o -f "$(<<< "{}" sed "s/\(.*\/[^.]*\).*//").mpg" ] && echo "{}"' \;

Se os arquivos listados são aqueles que devem ser excluídos, você pode prosseguir e executar isso:

find . -type f \( -name "*.cut" -o -name "*.cut.bak" \) -exec bash -c '[ -f "$(<<< "{}" sed "s/\(.*\/[^.]*\).*//").rec" -o -f "$(<<< "{}" sed "s/\(.*\/[^.]*\).*//").mpg" ] && rm "{}"' \;

Teste em uma hierarquia de diretórios criada ad hoc:

~/tmp$ tree
.
└── dir1
    ├── file1.cut
    ├── file1.cut.bak
    ├── file1.rec
    ├── file2.cut
    ├── file2.cut.bak
    ├── file2.mpg
    ├── file3.cut
    ├── file3.cut.bak
    └── subdir1
        ├── file1.cut
        ├── file1.cut.bak
        ├── file1.rec
        ├── file2.cut
        ├── file2.cut.bak
        ├── file2.mpg
        ├── file3.cut
        └── file3.cut.bak

2 directories, 16 files
~/tmp$ find . -type f \( -name "*.cut" -o -name "*.cut.bak" \) -exec bash -c 'if [ -f "$(<<< "{}" sed "s/\(.*\/[^.]*\).*//").rec" -o -f "$(<<< "{}" sed "s/\(.*\/[^.]*\).*//").mpg" ]; then rm "{}"; fi' \;
~/tmp$ tree
.
└── dir1
    ├── file1.rec
    ├── file2.mpg
    ├── file3.cut
    ├── file3.cut.bak
    └── subdir1
        ├── file1.rec
        ├── file2.mpg
        ├── file3.cut
        └── file3.cut.bak

2 directories, 8 files

Como você pode ver, todos os arquivos com extensão .cut ou .bak para o qual existe um arquivo com o mesmo nome e extensão .rec ou .mpg são excluídos recursivamente ( file1.cut e file1.cut.bak são excluídos por causa de file1.rec , file2.cut e file2.cut.bak são excluídos porque file2.mpg ; file3.cut e file3.cut.bak não são excluídos porque não há file3.rec ou file3.mpg no mesmo diretório)

    
por 28.06.2015 / 17:04
0

Se o comando for executado em algum pequeno dispositivo embutido com comandos e shells muito limitados (por exemplo, faltando find , shell mínimo à sash ), uma abordagem possível seria escrever algum C minúsculo (ou talvez C ++) fazendo isso, e compilar esse programa para um executável (seria bom fazer desse programa um software livre).

Você usará nftw para percorrer recursivamente a árvore de arquivos e criar uma matriz ( ou um vetor, ou uma lista) de caminhos a serem removidos. Em seguida, uma segunda passagem removeria efetivamente os arquivos. Funções relevantes são nftw (3) (para percorrer a árvore de arquivos), snprintf (3) (para construir nomes de arquivos), acesso (2) (para testar a existência de arquivo), stat (3) (para obter tipo, tamanho e outros meta-dados sobre um arquivo), remove(3) (para remover um arquivo), basename (3) , etc.

Se você tem o GNU find , você pode criar um shell script com ele (mas detalhes podem depender do seu shell, especialmente se ele é pequeno o suficiente para não ser compatível com POSIX). Colete os nomes dos arquivos a serem excluídos em algum arquivo temporário. Em seguida, remova-os depois.

Se você insistir em usar soluções shell, e supondo que o GNU find esteja disponível, você pode ter vários scripts de shell:

Primeiro, um script de shell (chamado de fora), nomeie-o como clean-the-mess.sh , o que criaria um arquivo temporário e invocaria outro script de shell interno consider-cleaning.sh para cada .cut & .cut.bak file:

#!/bin/sh
## untested clean-the-mess.sh script
## a temporary file listing files to remove
cleanlistfile=$(tempfile -s .cleanlist)
## on exit, or SIGQUIT, SIGTERM, or SIGINT signal, remove it
trap "rm $cleanlistfile" EXIT QUIT TERM INT
## find every file name .cut | .cut.bak; run consider-cleaning.sh on it
find -type f \( -name '*.cut' -o 'name '*.cut.bak' \) \
    -exec consider-cleaning.sh '{}' $cleanlistfile \;
## remove the collected file list
for f in $(cat $cleanlistfile) ; do rm $f ; done

Isso não funcionará se alguns arquivos tiverem espaços em seus nomes. Talvez considere xargs (1)

Em seguida, você precisa codificar o script consider-cleaning.sh interno, que adiciona caminhos de arquivo à lista de arquivos a serem limpos. Pode ser

#!/bin/sh
# internal untested consider-cleaning.sh script
file=$1
collectlist=$2
case $file in 
 *.cut) 
   bas=$(basename $file .cut)
   if [ ! -f "$bas.rec" -a ! -f "$bas.mpg" ]; then
      echo $file >> $collectlist
   fi
 ;;
 *.cur.bak)
   bas=$(basename $file .cut.bak)
   if [ ! -f "$bas.rec" -a ! -f "$bas.mpg" ]; then
      echo $file >> $collectlist
   fi
 ;;
 esac

Meus scripts não são provados, não foram testados, então provavelmente estão errados. Coloque #!/bin/sh -vx como primeira linha para testar & depure-os (você obterá algum rastreio de execução)

Como alternativa, insira um pequeno intérprete Lua com as poucas operações básicas relacionadas a arquivos primitivos, e escreva seu script em Lua. Lua é muito fácil de ser incorporada e pode ser feita para ser um pequeno intérprete.

    
por 28.06.2015 / 14:30

Tags