Como posso encontrar o (s) arquivo (s) mais recentemente modificado (s)?

0

Em um diretório, eu tenho vários arquivos e preciso fazer algo com o arquivo modificado mais recentemente com um sufixo .txt .

Idealmente, gostaria de fazer

myutility "$newest"

no final, em que $newest seria o nome do caminho do arquivo modificado mais recentemente.

Seria bom se isso adicionalmente pudesse ser generalizado para que eu pudesse obter o arquivo modificado mais recentemente com um sufixo .txt em uma hierarquia de diretórios, e melhor ainda se eu conseguisse, digamos, cinco arquivos modificados mais recentemente para poder usar

myutility "${newest[@]}"

para executar meu utilitário nos cinco arquivos .txt modificados mais recentemente em uma hierarquia de diretórios completa.

Uma solução usando bash ou ksh93 seria melhor.

    
por Kusalananda 18.07.2018 / 12:35

3 respostas

1

Embora você tenha marcado a pergunta bash e ksh , com zsh e qualificadores glob:

print **/*.txt(.om[1,5])

imprime os primeiros 5 arquivos simples ( . ) com extensão .txt , ordenados por tempo de modificação crescente ( om )

ex.

print **/*.txt(.om[1,5])
dir/file1.txt file2.txt dir/file.txt File1.txt File2.txt
    
por 18.07.2018 / 14:18
1

O shell bash (e um número de outros shells) tem um operador de teste -nt não padrão. Este operador testa se a hora da modificação em um arquivo é mais nova que a outra.

Em bash , o operador -nt tem uma resolução de tempo de um segundo. Em ksh93 , pode-se usar o mesmo operador com resolução de sub-segundo. O código abaixo é compatível com ksh93 , exceto que shopt -s globstar precisa mudar para set -o globstar quando esta opção é usada.

Usando o operador -nt test nos arquivos que correspondem a *.txt no diretório atual para encontrar o arquivo regular mais recente:

unset newest
for filename in ./*.txt; do
    if [ -f "$filename" ] && [ "$filename" -nt "$newest" ]; then
        newest=$filename
    fi
done

ou, um pouco mais curto,

unset newest
for filename in ./*.txt; do
    [ -f "$filename" ] && [ "$filename" -nt "$newest" ] && newest=$filename
done

No final do loop, o valor "$newest" seria o nome do arquivo regular modificado mais recentemente no diretório atual que tem um sufixo de nome de arquivo .txt , desde que esses arquivos existissem ( caso contrário, a variável newest não seria definida).

O shell dash , se isso for usado, precisaria de um teste separado para a existência do arquivo $newest , pois seu operador -nt tem semântica um pouco diferente de bash e ksh93 :

unset newest
for filename in ./*.txt; do
    if [ -f "$filename" ]; then
        if [ ! -f "$newest" ] || [ "$filename" -nt "$newest" ]; then
            newest=$filename
        fi
    fi
done

Para fazer isso de forma recursiva com bash , defina a opção globstar shell e use ** para fazer o globbing de nome de arquivo:

shopt -s globstar
unset newest
for pathname in ./**/*.txt; do
    if [ -f "$pathname" ] && [ "$pathname" -nt "$newest" ]; then
        newest=$pathname
    fi
done

O padrão ** corresponde a * , mas permite a correspondência entre / em nomes de caminho.

O shell dash não suporta isso.

Com base no código anterior, para obter os cinco arquivos modificados mais recentemente:

shopt -s globstar
unset newest
for pathname in ./**/*.txt; do
    if [ -f "$pathname" ]; then
        for (( i=0; i < 5; ++i )); do
            if [ "$pathname" -nt "${newest[$i]}" ]; then
                newest=( "${newest[@]:0:i}" "$pathname" "${newest[@]:i:4}" )
                break
            fi
        done
    fi
done

A única coisa extra aqui é que newest agora é uma matriz bash , e que nós, para cada nome de caminho que consideramos, temos que percorrer os cinco "arquivos mais recentes" encontrados mais recentemente para ver onde array este novo arquivo pode se encaixar.

Quando descobrimos que o arquivo é de fato mais novo do que um dos outros arquivos na matriz, combinamos o novo nome de caminho na matriz e ao mesmo tempo limitamos o número de elementos a cinco.

Após o término do loop, a matriz newest manterá os nomes de caminho dos cinco arquivos regulares modificados mais recentemente com um sufixo .txt nomes de arquivos. A matriz será classificada na hora da modificação, com o arquivo modificado mais recentemente como ${newest[0]} .

    
por 18.07.2018 / 12:35
0

Você pode listar os arquivos por hora de modificação (ou criação ou acesso) com ls.

diga simplesmente

ls -t *.txt | head -n5 

para obter os últimos 5 arquivos .txt recentes

Você pode alimentá-lo na myutility com $ () ou xargs.

ls -t *.txt | head -n5 | xargs myutility

Se você precisar da recursão, use o find.

find -type f -iname "*.txt" | xargs ls -t | head -n5 | xargs myutility

(possível problema: você precisa ter pelo menos um arquivo .txt para que isso funcione. Você pode consertá-lo, mas é a solução mais limpa).

EDIT: OP queria saber como lidar com nomes de arquivos com espaços. Aqui está uma solução:

find -type f -iname "*.txt" | xargs ls -t | head -n5 | tr '\n' '
ls -t *.txt | head -n5 
' | xargs -0 myutility

Se você quiser resolver o possível problema mencionado acima, pode verificar os arquivos antes do cabeçalho com find ..... | egrep '.*' || exit ou simplesmente incluir algum nome de arquivo sem sentido em ls e ignorar o aviso como xargs ls -t '' .

    
por 18.07.2018 / 14:04