usando stat para fornecer timestamp para toque

11

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

No entanto, preciso preservar o registro de data e hora original para modificado. Atualmente, estou tentando usar o stat e tocar como 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 touch falha. executando os comandos separadamente, notei que "stat -c" é algo parecido com isto:

1334758696

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

Tim Alexander
fonte
Além: seu uso IFSparece incomum. Deseja realmente dividir em backspace ( \b)? Veja unix.stackexchange.com/questions/9496/… para obter algumas dicas.
18712 Mikel

Respostas:

17

stat'soutput é um registro de data e hora do Unix, também chamado de segundos desde a época .

Todos os coreutils GNU que aceitam uma data permitem que você coloque um carimbo de data / hora, prefixando-o com um @.

Então tente isso

touch -d @$ORIGTS $f

Veja coreutils - Segundos desde a época

Mikel
fonte
ah, isso explica muitos timestamps que eu já vi no linux agora! Muito obrigado
Tim Alexander
8

touchpode usar o carimbo de data e hora de um arquivo usando a -ropção Você pode enviar para um arquivo diferente (suponho abaixo que -ifseja um arquivo de entrada e -ofseja um 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
Glenn Jackman
fonte
+1 para evitar stat.
precisa saber é o seguinte
3

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

Desde que você está assumindo um shell com echo -e, e você tem bash na sua linha shebang de qualquer maneira, você pode usá-lo IFS=$'\n\b'. Tornar o backspace um separador é bastante estranho. Você não precisa IFSdo que está fazendo de qualquer maneira.

OLDIFS=$IFS
...
IFS=$OLDIFS

Observe que isso restaura o valor antigo de IFSapenas se IFSfoi definido inicialmente. Se IFSinicialmente não foi definido, isso define IFSa sequência vazia, que é completamente diferente. No ksh, bash ou zsh, se você precisar configurar IFStemporariamente, poderá escrever seu código em uma função e tornar IFSlocal essa função. Em outras conchas, você precisa ter cuidado com o caso não definido.

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

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

  • Isso divide a saída nos caracteres em $IFS. Se você definir IFSuma nova linha, isso dividirá a saída em novas linhas, mas você ainda não poderá lidar com 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 um padrão global. Se você arquivos chamados A[12].pdf, A1.pdfe A2.pdf, você vai acabar com A1.pdf A2.pdf A1.pdf A2.pdf. Você pode desativar o globbing com set -f(e voltar set +fa usar com ), mas aqui (como na maioria das vezes) o caminho certo é não usar a substituição de comando.

Use o -execargumento para find(ou, se o seu sistema tiver -print0, você pode usá-lo find … -print0 | xargs -0 …; isso só é útil para atuar em vários arquivos de uma só vez, se você precisar de portabilidade para sistemas Linux antigos ou sistemas OpenBSD atuais que ainda -print0não possuem -exec … {} +).

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

Observe que faltam aspas duplas $f(elas não são necessárias se estes são os resultados da divisão e você não mudou IFSdesde então e o globbing está desativado, mas, na verdade, sempre coloque aspas duplas, a menos que você saiba por que pode ' não os deixe ligados).

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

  • Se possível, primeiro transforme o arquivo original em um novo arquivo, depois chame touch -rpara definir a data do novo arquivo e, finalmente, mova o novo arquivo para o local. É melhor garantir que a saída esteja correta antes que algo aconteça na entrada; caso contrário, se a transformação for interrompida por qualquer motivo (por exemplo, falta de energia), você perderá dados.
  • Se a transformação for uma caixa preta sobre a qual você não tem controle, poderá usar touch -rduas vezes: uma vez para salvar a data do arquivo original em um arquivo temporário vazio (que será criado automaticamente) e depois após a transformação para restaurar a data usando o arquivo temporário.

Portanto:

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"' {} \;
Gilles 'SO- parar de ser mau'
fonte
0

Por alguma razão, perdi a resposta sobre touch -r; se, por algum motivo estranho, você não tiver o GNU coreutils ' statcomo na resposta aceita, nem puder usar touch -r, aqui está como obter o carimbo de data / hora no touchformato amigável com um BSD-like stat.

% /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 realmente, basta usar touch -r:

% touch foo
% touch -r johnson foo
% /usr/bin/stat -f '%Sm' foo
Oct 23 22:51:00 2012
Nicholas Riley
fonte
0

Eu tive o mesmo problema, vindo do processo de 'criação de filmes'.

No exemplo abaixo orig_file.wavestá o arquivo com registro de data e hora original, enquanto processed_file.wavo arquivo com o mesmo conteúdo, mas com registro de data e hora incorreto.

ANTES:

localhost $ ls -lh orig_file.wav processed_file.wav Jan 23 17:15 processed_file.wav Jul 9 2018 orig_file.wav

O COMANDO:

localhost $ touch -t $(date --date=@`stat -f%B orig_file.wav` +%Y%m%d%H%M.%S) processed_file.wav

DEPOIS DE:

localhost $ ls -lh orig_file.wav processed_file.wav Jul 9 2018 processed_file.wav Jul 9 2018 orig_file.wav

NOTAS:

statem ticks invertidos fornece o registro de data e hora de criação do arquivo original como tempo de época unix (em segundos). O @ do coreutils o converte em uma data iso que datepode entender e reformatar com YYYYMMDDHHmm.SS para que ele touchpossa entendê-lo. Coloquei o datecomando em $ (), como um equivalente a ticks invertidos, pois eles não podem ser reutilizados no mesmo comando.

dominikz
fonte
(1) Isso parece ser quase exatamente o mesmo que a resposta de Nicholas Riley, mas mais complicado. Por que alguém iria querer usar isso e não isso (ou, melhor ainda, a resposta de glenn jackman , usando touch -r)? (2)  stat pode ser colocado $(…); eles podem ser usados ​​várias vezes em um comando.
G-Man diz 'Reinstate Monica'
Além da resposta dele, usando o tempo de modificação, em vez de criar tempo, você parece estar correto. Não notei essa outra resposta. Você pode votar no meu.
dominikz 29/01/19
Bem, se você me pedir, não é divertido. :-) ⁠
G-Man diz 'Restabelecer Monica'