utilizzando stat per fornire la marca temporale per il tocco


11

Sto cercando di OCR alcuni documenti insitu (da una riga di comando di Linux su una condivisione di Windows). Il processo di OCRing è find e ho confuso usando il comando find per reindirizzare correttamente i file attraverso il loop.

Tuttavia, devo conservare il timestamp originale per le modifiche. Attualmente sto cercando di utilizzare stat e toccare come di seguito:

#!/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

Naturalmente il comando touch non riesce. eseguendo i comandi separatamente noto che "stat -c" è qualcosa sulla falsariga di questo:

1334758696

che è come nessuna data che conosco. Mi sento come se fossi vicino ma non riesco a capire come convertire la data che ho in una versione touch-friendly. È una qualche forma di secondo da qualcosa?


A parte: il tuo uso IFSsembra insolito. Volevi davvero dividere su backspace ( \b)? Consulta unix.stackexchange.com/questions/9496/… per alcuni suggerimenti.
Mikel,

Risposte:


17

stat'sl'output è un timestamp Unix, chiamato anche secondi dall'epoca .

Tutti i coreutils GNU che accettano una data ti permettono di mettere un timestamp invece anteponendo il timestamp con un @.

Quindi prova questo

touch -d @$ORIGTS $f

Vedi coreutils - I secondi dall'epoca


ah, questo spiega molti timestamp che ho visto su Linux ora! Grazie mille
Tim Alexander,

8

touchpuò usare il timestamp di un file usando l' -ropzione Potresti voler eseguire l'output in un file diverso (suppongo di seguito che -ifsia un file di input e -ofsia un file di output)

for f in ...; do
    sudo /opt/ABBYYOCR9/abbyyocr9 ... -if $f ... -of $f.new
    touch -r $f $f.new
    mv $f.new $f
done

+1 per evitare stat.
l0b0,

3

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

Dato che stai assumendo una shell con echo -e, e hai comunque bash nella tua linea shebang, puoi usare IFS=$'\n\b'. Rendere il backspace un separatore è piuttosto strano. Non hai bisogno IFSdi quello che stai facendo comunque.

OLDIFS=$IFS
...
IFS=$OLDIFS

Si noti che ciò ripristina il vecchio valore di IFSsolo se IFSinizialmente era impostato. Se IFSinizialmente non era impostato, questo si imposta IFSsulla stringa vuota, che è completamente diversa. In ksh, bash o zsh, se è necessario impostare IFStemporaneamente, è possibile scrivere il codice in una funzione e renderlo IFSlocale per questa funzione. In altre shell, è necessario fare attenzione al caso non impostato.

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

Non usare mai la sostituzione dei comandi sull'output di find.

  • Questo divide l'output in corrispondenza dei caratteri $IFS. Se si imposta IFSsu una nuova riga, questo divide l'output su nuove righe, ma non è ancora possibile gestire nomi di file contenenti nuove righe.
  • Non solo il risultato della sostituzione dei comandi viene suddiviso in parole, ma ogni parola viene utilizzata come modello glob. Se si file chiamati A[12].pdf, A1.pdfe A2.pdf, vi ritroverete con A1.pdf A2.pdf A1.pdf A2.pdf. Puoi disattivare il globbing con set -f(e riaccendere con set +f), ma qui (come la maggior parte delle volte) il modo giusto non è usare la sostituzione dei comandi.

Usa l' -execargomento per find(o se il tuo sistema ha -print0, puoi find … -print0 | xargs -0 …invece usare ; questo è utile per agire su più file contemporaneamente se hai bisogno di portabilità su antichi sistemi Linux o sistemi OpenBSD attuali che hanno -print0ma non -exec … {} +).

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

Tieni presente che ti mancano doppie virgolette $f(non sono necessarie se questi sono i risultati della divisione e non sei cambiato IFSda allora e il globbing è disattivato, ma in realtà metti sempre doppie virgolette a meno che tu non sappia perché puoi " non lasciarli accesi).

Questo è goffo e non portatile ( statnon esiste su tutti i sistemi e i suoi argomenti sono diversi nei diversi sistemi in cui esiste). touchha un'opzione portatile per impostare un file per il timestamp di un altro file: touch -r REFERENCE_FILE FILE. Raccomanderei invece uno dei due approcci:

  • Se possibile, prima trasforma il file originale in un nuovo file, quindi chiama touch -rper impostare la data del nuovo file e infine spostare il nuovo file in posizione. È meglio assicurarsi che l'output sia corretto prima che accada qualcosa; in caso contrario, se la trasformazione viene interrotta per qualsiasi motivo (ad es. mancanza di corrente), si perderanno i dati.
  • Se la trasformazione è una scatola nera su cui non hai alcun controllo, puoi usarla touch -rdue volte: una volta per salvare la data del file originale su un file temporaneo vuoto (che verrà creato automaticamente), quindi di nuovo dopo la trasformazione per ripristinare la data utilizzando il file temporaneo.

Così:

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"' {} \;

0

Per qualche motivo mi mancava la risposta touch -r; se per qualche strana ragione non hai né i coreutils GNU ' statcome nella risposta accettata né puoi usare touch -r, ecco come ottenere il timestamp in touchformato compatibile con un tipo BSD 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

Ma davvero, basta usare touch -r:

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

0

Ho avuto lo stesso problema, proveniente dai "processi" di produzione cinematografica.

Nell'esempio che segue orig_file.wavè il file con il timestamp originale, mentre processed_file.wavè il file con lo stesso contenuto, ma il timestamp sbagliato.

PRIMA:

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

IL COMANDO:

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

DOPO:

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

APPUNTI:

statin tick invertiti ti dà il timestamp di creazione del file originale come tempo di epoca unix (in secondi). @ Da coreutils lo converte in una data ISO che datepuò comprendere e riformattare con AAAAMMGGHHmm.SS in modo che touchpossa capirlo. Ho messo il datecomando in $ (), come equivalente di tick invertiti, in quanto non possono essere riutilizzati nello stesso comando.


(1) Questo sembra essere quasi identico alla risposta di Nicholas Riley ma più complicato. Perché qualcuno dovrebbe voler usare questo piuttosto che quello (o, meglio ancora, la risposta di Glenn Jackman , usando touch -r)? (2)  stat può essere inserito $(…); possono essere usati più volte in un solo comando.
G-Man dice "Ripristina Monica" il

A parte la sua risposta usando il tempo di modifica piuttosto che creare il tempo, sembra che tu abbia ragione. Non ho notato questa altra risposta. Puoi sottovalutare il mio.
dominikz,

Bene, se me lo chiedi, non è divertente. :-) ⁠
G-Man dice "Ripristina Monica" il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.