utiliser stat pour fournir un horodatage pour le toucher

11

J'essaie d'OCR certains documents in situ (à partir d'une ligne de commande Linux sur un partage Windows). Le processus d'OCRing est find et je me suis trompé en utilisant la commande find pour diriger correctement les fichiers dans la boucle.

Cependant, je dois conserver l'horodatage d'origine pour les modifications. J'essaie actuellement d'utiliser stat et toucher comme ci-dessous:

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

Bien sûr, la commande tactile échoue. en exécutant les commandes séparément, je remarque que "stat -c" est quelque chose du genre:

1334758696

qui ne ressemble à aucune date que je connaisse. J'ai l'impression d'être proche, mais je n'arrive pas à savoir comment convertir la date que j'ai en une version tactile. Est-ce une forme de secondes de quelque chose?

Tim Alexander
la source
À part: votre utilisation IFSsemble inhabituelle. Vouliez-vous vraiment vous séparer sur backspace ( \b)? Voir unix.stackexchange.com/questions/9496/… pour quelques conseils.
Mikel

Réponses:

17

stat'sLa sortie est un horodatage Unix, également appelé secondes depuis l'époque .

Tous les coreutils GNU qui acceptent une date vous permettent de mettre un horodatage à la place en préfixant l'horodatage avec un @.

Alors essayez ceci

touch -d @$ORIGTS $f

Voir coreutils - Secondes depuis l'époque

Mikel
la source
ah cela explique beaucoup d'horodatages que j'ai vus sous linux maintenant! Merci beaucoup
Tim Alexander
8

touchpeut utiliser l'horodatage d'un fichier en utilisant l' -roption. Vous voudrez peut-être sortir dans un fichier différent (je suppose que ci-dessous c'est le -iffichier d'entrée et le -offichier de sortie)

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
la source
+1 pour éviter stat.
l0b0
3

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

Puisque vous supposez un shell avec echo -e, et que vous avez quand même bash dans votre ligne de shebang, vous pouvez utiliser IFS=$'\n\b'. Faire du retour arrière un séparateur est plutôt bizarre. De toute façon, vous n'avez pas besoin IFSde ce que vous faites.

OLDIFS=$IFS

IFS=$OLDIFS

Notez que cela restaure l'ancienne valeur de IFSuniquement si elle a IFSété initialement définie. Si IFSétait initialement non défini, cela définit IFSla chaîne vide, ce qui est complètement différent. En ksh, bash ou zsh, si vous avez besoin de définir IFStemporairement, vous pouvez écrire votre code dans une fonction et rendre IFSlocal cette fonction. Dans d'autres coquilles, vous devez faire attention au cas non réglé.

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

N'utilisez jamais de substitution de commande sur la sortie de find.

  • Cela divise la sortie au niveau des caractères dans $IFS. Si vous définissez IFSune nouvelle ligne, cela divise la sortie aux nouvelles lignes, mais vous ne pouvez toujours pas gérer les noms de fichiers contenant des nouvelles lignes.
  • Non seulement le résultat de la substitution de commande est divisé en mots, mais chaque mot est ensuite utilisé comme modèle global. Si vous fichiers appelés A[12].pdf, A1.pdfet A2.pdf, vous vous retrouverez avec A1.pdf A2.pdf A1.pdf A2.pdf. Vous pouvez désactiver la globalisation avec set -f(et la réactiver avec set +f), mais ici (comme la plupart du temps) la bonne façon n'est pas d'utiliser la substitution de commandes.

Utilisez l' -execargument pour find(ou si votre système a -print0, vous pouvez utiliser à la find … -print0 | xargs -0 …place; cela n'est utile que pour agir sur plusieurs fichiers à la fois si vous avez besoin de portabilité vers les anciens systèmes Linux ou les systèmes OpenBSD actuels qui en ont -print0mais pas -exec … {} +).

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

Notez que vous manquez des guillemets doubles $f(ils ne sont pas nécessaires si ce sont les résultats du fractionnement et que vous n'avez pas changé IFSdepuis et que la globalisation est désactivée, mais vraiment, mettez toujours des guillemets doubles sauf si vous savez pourquoi vous pouvez '' ne les laissez pas allumés).

Ceci est maladroit et non portable ( statn'existe pas sur tous les systèmes, et ses arguments sont différents selon les différents systèmes où il existe). toucha une option portable pour définir un fichier à l'horodatage d'un autre fichier: touch -r REFERENCE_FILE FILE. Je recommanderais plutôt l'une des deux approches:

  • Si vous le pouvez, commencez par transformer le fichier d'origine en un nouveau fichier, puis appelez touch -rpour définir la date du nouveau fichier, et enfin déplacez le nouveau fichier en place. Il est préférable de s'assurer que la sortie est correcte avant que quoi que ce soit arrive à l'entrée; sinon, si la transformation est interrompue pour une raison quelconque (par exemple une panne de courant), vous perdrez des données.
  • Si la transformation est une boîte noire sur laquelle vous n'avez aucun contrôle, vous pouvez utiliser touch -rdeux fois: une fois pour enregistrer la date du fichier d'origine sur un fichier temporaire vide (qui sera automatiquement créé), puis à nouveau après la transformation pour restaurer la date en utilisant le fichier temporaire.

Donc:

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- arrête d'être méchant'
la source
0

Pour une raison quelconque, j'ai raté la réponse touch -r; si, pour une raison étrange, vous n'avez pas de coreutils GNU statcomme dans la réponse acceptée et que vous ne pouvez pas utiliser touch -r, voici comment obtenir l'horodatage au touchformat convivial avec un 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

Mais vraiment, utilisez simplement touch -r:

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

J'ai eu le même problème, venant du processus de "réalisation de films".

Dans l'exemple ci orig_file.wav- dessous se trouve le fichier avec l'horodatage d'origine, tandis que processed_file.wavle fichier avec le même contenu, mais un horodatage incorrect.

AVANT:

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

LA COMMANDE:

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

APRÈS:

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

REMARQUES:

staten ticks inversés vous donne l'horodatage de création du fichier d'origine en temps d'époque unix (en secondes). Le @ de coreutils le convertit en une date iso qui datepeut comprendre et reformater avec YYYYMMDDHHmm.SS afin de touchpouvoir le comprendre. J'ai mis la datecommande dans $ (), comme un équivalent de ticks inversés, car ils ne peuvent pas être réutilisés dans la même commande.

dominikz
la source
(1) Cela semble être presque exactement la même chose que la réponse de Nicholas Riley mais plus compliqué. Pourquoi voudrait-on utiliser ceci plutôt que cela (ou, mieux encore, la réponse de Glenn Jackman , en utilisant touch -r)? (2)  stat peut être installé $(…); ils peuvent être utilisés plusieurs fois dans une seule commande.
G-Man dit `` Réintègre Monica '' le
À part sa réponse en utilisant l'heure de modification plutôt que de créer l'heure, vous semblez avoir raison. Je n'ai pas remarqué cette autre réponse. Vous pouvez voter contre le mien.
dominikz
Eh bien, si vous me le demandez, ce n'est pas amusant. :-) ⁠
G-Man dit 'Reinstate Monica'