usando stat para fornecer timestamp para toque

10

Estou tentando OCR alguns documentos insitu (a partir de uma linha de comando do Linux em um compartilhamento do Windows). O processo de OCR é encontrado e eu tenho confuso usando o comando find para canalizar os arquivos através do loop corretamente.

No entanto, preciso preservar o timestamp original para modificado. No momento, estou tentando usar stat e touch conforme abaixo:

#!/bin/bash
OLDIFS=$IFS

    IFS=$(echo -en "\n\b")

    for f in 'find /mnt/library/Libra/Libra/Ashfords -name "*.pdf"'
         do
        ORIGTS='stat -c "%Y" $f'
        sudo /opt/ABBYYOCR9/abbyyocr9 -rl English -pi -if $f -f PDFA -paemImageOnText -pafpr original -of $f
        touch -t $ORIGTS $f

    done

    IFS=$OLDIFS

É claro que o comando de toque falha. rodando os comandos separadamente percebo "stat -c" é algo ao longo das linhas deste:

1334758696

que é como nenhuma data que eu conheço. Sinto-me como se estivesse perto, mas não consigo descobrir como converter a data em que tenho uma versão amigável ao toque. É alguma forma de segundos de alguma coisa?

    
por Tim Alexander 18.04.2012 / 17:05

4 respostas

14

stat's output é um timestamp do Unix, também chamado segundos desde a Epoch .

Todos os coreutils GNU que aceitam uma data permitem que você coloque um timestamp, prefixando o timestamp com um @ .

Então tente isso

touch -d @$ORIGTS $f

Veja coreutils - Segundos desde a época

    
por 18.04.2012 / 17:17
8

touch pode usar o registro de data e hora de um arquivo usando a opção -r . Você pode querer dar saída para um arquivo diferente (suponho que -if seja o arquivo de entrada e -of seja o arquivo de saída)

for f in ...; do
    sudo /opt/ABBYYOCR9/abbyyocr9 ... -if $f ... -of $f.new
    touch -r $f $f.new
    mv $f.new $f
done
    
por 18.04.2012 / 17:30
3

IFS=$(echo -en "\n\b")

Como você está assumindo um shell com echo -e e, de qualquer maneira, você tem o bash em sua linha shebang, você pode usar IFS=$'\n\b' . Fazendo backspace um separador é bastante estranho. Você não precisa de IFS para o que está fazendo de qualquer maneira.

OLDIFS=$IFS

IFS=$OLDIFS

Observe que isso restaura o valor antigo de IFS apenas se IFS foi definido inicialmente. Se IFS foi inicialmente desfeito, isso define IFS como a string vazia, o que é completamente diferente. Em ksh, bash ou zsh, se você precisar definir IFS temporariamente, poderá escrever seu código em uma função e tornar IFS local nessa função. Em outros shells, você precisa ter cuidado com o caso não definido.

'find /mnt/library/Libra/Libra/Ashfords -name "*.pdf"'

Nunca use a substituição de comando na saída de find .

  • Isso divide a saída nos caracteres em $IFS . Se você definir IFS para uma nova linha, isso dividirá a saída em novas linhas, mas você ainda não poderá manipular nomes de arquivos que contenham novas linhas.
  • Não apenas o resultado da substituição de comandos é dividido em palavras, mas cada palavra é usada como padrão glob. Se você tiver arquivos chamados A[12].pdf , A1.pdf e A2.pdf , você acabará com A1.pdf A2.pdf A1.pdf A2.pdf . Você pode desativar globbing com set -f (e voltar com set +f ), mas aqui (como na maioria das vezes) o caminho certo é não usar a substituição de comandos.

Use o argumento -exec para find (ou se o seu sistema tiver -print0 , você pode usar find … -print0 | xargs -0 … ; isso é útil apenas para atuar em vários arquivos de uma vez se você precisar de portabilidade para antigos sistemas Linux ou sistemas atuais do OpenBSD que possuem -print0 mas não -exec … {} + ).

ORIGTS='stat -c "%Y" $f'
# [transform $f]
touch -t $ORIGTS $f

Observe que você está perdendo aspas duplas em torno de $f (elas não são necessárias se esses forem os resultados da divisão e você não tiver alterado IFS desde então e a globbing estiver desativada, mas, na verdade, sempre aspas duplas, a menos que você saiba por que não pode deixá-las ativadas).

Isso é desajeitado e não portátil ( stat não existe em todos os sistemas e seus argumentos são diferentes nos diferentes sistemas em que ele existe). touch tem uma opção portátil para definir um arquivo para o registro de data e hora de outro arquivo: touch -r REFERENCE_FILE FILE . Eu recomendaria uma de duas abordagens:

  • Se puder, primeiro transforme o arquivo original em um novo arquivo, em seguida, chame touch -r para definir a data do novo arquivo e, finalmente, mova o novo arquivo para o lugar. É melhor ter certeza de que a saída está boa antes que algo aconteça com a entrada; caso contrário, se a transformação for interrompida por algum motivo (por exemplo, uma falha de energia), você perderá dados.
  • Se a transformação for uma caixa preta sobre a qual você não tem controle, use touch -r duas vezes: uma vez para salvar a data do arquivo original em um arquivo temporário vazio (que será criado automaticamente), depois novamente a transformação para restaurar a data usando o arquivo temporário.

Assim:

find /mnt/library/Libra/Libra/Ashfords -name '*.pdf' \
     -exec sh -c 'transform "$0" to "$0.tmp" && touch -r "$0" "$0.tmp" && mv -f "$0.tmp" "$0"' {} \;
    
por 19.04.2012 / 03:00
0

Por algum motivo, perdi a resposta sobre touch -r ; se por algum motivo estranho você não tiver o stat do GNU coreutils como na resposta aceita nem pode usar touch -r , aqui está como obter o timestamp no formato touch -friendly com um stat do tipo BSD.

% /usr/bin/stat -f '%Sm' johnson                   
Oct 23 22:51:00 2012
% /usr/bin/stat -t '%Y%m%d%H%M.%S' -f '%Sm' johnson
201210232251.00
% touch foo
% touch -t $(/usr/bin/stat -t '%Y%m%d%H%M.%S' -f '%Sm' johnson) foo
% /usr/bin/stat -f '%Sm' foo                    
Oct 23 22:51:00 2012

Mas, na verdade, use apenas touch -r :

% touch foo
% touch -r johnson foo
% /usr/bin/stat -f '%Sm' foo
Oct 23 22:51:00 2012
    
por 07.07.2018 / 22:12