Curinga: caminho de origem de retorno

1

Estou tentando renomear cada arquivo access.log.gz (nota: nome de arquivo exato, não "começando com" ou "contendo") encontrado em /home/*/logs to date-access.log.gz na mesma pasta.

for file in /home/*/logs/access.log.gz
do
   mv -v "$file" /home/*/logs/old/'date +\%G-\%m-\%d'"-access.log.gz"
done

Claro que estou recebendo /home/*/logs/2014-09-08-access.log.gz - No such file or directory . Como posso chamar os * caminhos de volta? Cada arquivo deve ser renomeado e movido para / old / subdir da pasta de origem. Eu tentei com

mv -v "$file" /home/''/logs/old/'date +\%G-\%m-\%d'"-access.log.gz"

... mas não funcionou.

    
por MultiformeIngegno 08.09.2014 / 22:02

3 respostas

2

Use find ( Como posso usar o comando find com mais eficiência? ? ).

find /home/ -ipath */logs/access.log.gz

Isso deve encontrar todos os arquivos de seu interesse e imprimi-los. Você poderia inserir isso no seu script, mas é provavelmente mais fácil deixar find fazer todo o trabalho pesado.

find /home/ -ipath */logs/access.log.gz -execdir mv "{}" "old/'date +\%G-\%m-\%d'-access.log.gz" \;

Os recursos de find que estamos usando aqui são:

  • -ipath corresponde a padrões nos nomes de arquivos encontrados. Você também pode usar -name se tiver certeza de que há apenas um arquivo access.log.gz em cada subcaminho ( -name access.log.gz ).
  • -execdir executa o comando fornecido em cada arquivo encontrado, a partir do subdiretório que contém o arquivo correspondente. Isso equivale a fazer cd para onde cada arquivo é e, em seguida, executar o comando lá. Nesse caso, ele economiza muita lógica de manipulação de caminho. O arquivo encontrado é substituído por {}. Observe também que "old" é dado como um caminho relativo (como você disse que old/ existe em logs/ )
por roadmr 08.09.2014 / 22:12
1

Basta dissecar e remontar $file enquanto você repassa os arquivos correspondentes: ${file%/*} te dá $ arquivo com tudo depois do último / removido, e ${file##*/} te dá $ arquivo com tudo antes do último / removido; juntos, ${file%/*}/old/$date-${file##*/} lhe dará o "novo" nome de arquivo correspondente a $file .

Presumivelmente, a data não vai mudar no decorrer da execução do seu script, então não faz sentido invocar date para cada arquivo; em vez disso, armazene a data em uma variável uma vez e use-a durante o loop: date=$(date '+%G-%m-%d') . (Observe que os scripts modernos devem usar $(...) em vez de backticks. Observe também que % não é um caractere "especial" e, portanto, não precisa ser citado ou salvo, embora seja uma boa prática citado.)

Se você tiver uma nova versão do Bash, poderá evitar a sub-shell totalmente usando printf -v date '%(%G-%m-%d)T' -1 .

Você também pode achar útil usar shopt -s globstar para poder pesquisar a profundidade arbitrária nos diretórios e shopt -s nullglob para que o glob sem correspondência (curinga) seja expandido para "nada" em vez do padrão glob original. / p>

Colocando tudo isso juntos, conseguimos:

shopt -s globstar nullglob
date=$( date '+%G-%m-%d' )
for file in /home/*/logs/**/access.log.gz
do
    target=${file%/*}/old/$date-${file##*/}
    mv -vi "$file" "$target"
done
    
por Martin 08.09.2014 / 22:38
0

Se você tiver zsh instalado, use zmv . Em um script:

#!/bin/zsh
autoload zmv
zmv '/home/*/logs/access.log.gz' '$f:h/'date +\%G-\%m-\%d'-$f:t'

Na linha de comando zsh, coloque autoload zmv no seu ~/.zshrc e execute a última linha no prompt de comando.

    
por Gilles 08.09.2014 / 23:18