Listando arquivos sem o caminho completo com auxílio do laço de repetição FOR (bash)

Programadores shellscript e administradores de servidores Linux em geral, sentem dificuldades para solucionar pequenos problemas que as vezes parecem ser “tão fácil”, mas que na hora de colocar a “mão na massa” pra resolver, não é tão facil assim.

Postarei aqui alguns dos cenários que me deparo, no intuito de auxiliar o pessoal que pesquisa e se interessa pelo assunto.

Então vamos lá.. Há alguns dias me deparei com um simples “ls” que eu precisava fazer em um determinado diretório para verificar todos os arquivos com extensão .txt e compactá-los com gzip, mas com destino em outro diretório de backup.

E aí? Simples não? Poisé, teoricamente sim, mas na prática complica um pouquinho. Vou explicar o motivo…

A estrutura de diretórios era essa semelhante à essa:

root@vostrolab:/# ls -la /tmp/cialinux/
total 1
drwxr-xr-x  2 root root 240 2009-05-22 21:11 .
drwxrwxrwt 18 root root 704 2009-05-22 21:07 ..
-rw-r–r–  1 root root   0 2009-05-22 21:11 linux1.sh
-rw-r–r–  1 root root   0 2009-05-22 20:49 linux1.txt
-rw-r–r–  1 root root   0 2009-05-22 21:11 linux2.sh
-rw-r–r–  1 root root   0 2009-05-22 20:49 linux2.txt
-rw-r–r–  1 root root   0 2009-05-22 21:11 linux3.sh
-rw-r–r–  1 root root   0 2009-05-22 20:49 linux3.txt
root@vostrolab:/#

E o desafio era ensinar um shellscript a compactar apenas os arquivos com extensão .txt (porém todos eles pois podem ser 3, mas podem ser 1.000.000) desse diretório e jogar no diretório de backup: /tmp/site_backup.

Ao tentar fazer da seguinte forma, não se tem sucesso:

root@vostrolab:/# for arquivo in `ls /tmp/cialinux/*.txt`; do gzip -c $arquivo > /tmp/site_backup/$arquivo.gz; done
bash: /tmp/site_backup//tmp/cialinux/linux1.txt.gz: No such file or directory
bash: /tmp/site_backup//tmp/cialinux/linux2.txt.gz: No such file or directory
bash: /tmp/site_backup//tmp/cialinux/linux3.txt.gz: No such file or directory

Isso por causa do retorno do comando “ls” que vem com o full-path (caminho completo) do arquivo.. conforme abaixo:

root@vostrolab:/# for arquivo in `ls /tmp/cialinux/*.txt`; do echo $arquivo; done
/tmp/cialinux/linux1.txt
/tmp/cialinux/linux2.txt
/tmp/cialinux/linux3.txt
root@vostrolab:/#

Para evitar e resolver de forma simples o problema, uma das maneiras existentes é usar o seguinte recurso do próprio shell:

root@vostrolab:/# for arquivo in `ls /tmp/cialinux/*.txt`; do echo ${arquivo##/*/}; done
linux1.txt
linux2.txt
linux3.txt
root@vostrolab:/#

E o comando com a compressão GZIP ficaria assim:

root@vostrolab:/# for arquivo in `ls /tmp/cialinux/*.txt`; do gzip -c $arquivo > /tmp/site_backup/${arquivo##/*/}.gz; done

root@vostrolab:/# ls -la /tmp/site_backup/
total 13
drwxr-xr-x  2 root root 144 2009-05-22 21:22 .
drwxrwxrwt 18 root root 704 2009-05-22 21:07 ..
-rw-r–r–  1 root root  31 2009-05-22 21:22 linux1.txt.gz
-rw-r–r–  1 root root  31 2009-05-22 21:22 linux2.txt.gz
-rw-r–r–  1 root root  31 2009-05-22 21:22 linux3.txt.gz
root@vostrolab:/#

Estamos abertos para que o pessoal comente sobre outras maneiras de solucionar o mesmo problema …

Por: Hudson Murilo dos Santos

Fonte de pesquisa:
* Sessão “Parameter Expansion” do manual do BASH (man bash)

3 thoughts on “Listando arquivos sem o caminho completo com auxílio do laço de repetição FOR (bash)

  1. 2 soluções que eu acho mais simples:

    1) Ir ao diretório /tmp/cialinux
    2) Usar basename

    Eu usaria a primeira, que seria assim:

    cd /tmp/cialinux
    for arq in *.txt
    do
    gzip -c $arq > /tmp/site_backup/$arq.gz
    done

    E a 2ª solução:

    for arq in /tmp/cialunux/*.txt
    do
    arq=$(basename $arq)
    gzip -c $arq > /tmp/site_backup/$arq.gz
    done

    Você pode armazenar todos os *.txt em um único arquivo gz também. Acho que simplifica, e no caso de backups, pode-se usar a data atual como nome do arquivo.

    Algo assim:
    gzip -c /tmp/cialinux/*.txt > /tmp/site_backup/$(date +’%y_%m_%d’).gz


    Fedalto

  2. A primeira solução é a mais simples mas eu particularmente não gosto de mudar de diretório durante a execução de um shell. Questão de organização e evite de futuros problemas que possam acontecer case seu shell esteja em outro diretório.

    É mais uma coisa a ser controlada concorda?

    Legal a segunda solução com o basename! Eu nunca tinha utilizado.

    A última solução que você passou no meu caso não seria úteis, pois o artigo foi escrito como sendo um “backup” mas na verdade o que eu estava fazendo quando me deparei com essa situação era um shellscript replicação de banco de dados Oracle, então eu precisava de cada “archive” compactado individualmente, sem ser empacotado tudo em um só, para posteriormente fazer a aplicação dele na base de dados montada em standby.

    Obrigado pela contribuição.

Leave a Comment

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *