web-dev-qa-db-ja.com

statを使用してタッチのタイムスタンプを提供する

一部のドキュメントをその場でOCRしようとしています(Windows共有のLinuxコマンドラインから)。 OCR処理のプロセスはfindであり、findコマンドを使用してファイルをループに正しくパイプすることで混乱しています。

ただし、変更のために元のタイムスタンプを保持する必要があります。私は現在、以下のようにstatとtouchを使用しようとしています:

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

もちろんタッチコマンドは失敗します。コマンドを個別に実行すると、 "stat -c"が次のようになります。

1334758696

それは私が知らない日付のようなものです。近くにいるような気がしますが、日付をタッチフレンドリーなバージョンに変換する方法がわかりません。何かからの秒の形ですか?

11
Tim Alexander

stat's出力は、Unixタイムスタンプであり、エポックからの秒数とも呼ばれます。

すべてのGNU日付を受け入れるcoreutilsでは、タイムスタンプの前に@を付けることにより、タイムスタンプを置くことができます。

だからこれを試してください

touch -d @$ORIGTS $f

coreutils-エポックからの秒数 を参照してください

17
Mikel

touchは、-rオプションを使用してファイルのタイムスタンプを使用できます。別のファイルに出力したい場合があります(以下では、-ifが入力ファイルで、-ofが出力ファイルであると想定しています)

for f in ...; do
    Sudo /opt/ABBYYOCR9/abbyyocr9 ... -if $f ... -of $f.new
    touch -r $f $f.new
    mv $f.new $f
done
8
glenn jackman

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

echo -eを含むシェルを想定していて、とにかくシバン行にbashがあるので、IFS=$'\n\b'を使用できます。バックスペースをセパレーターにするのは奇妙です。とにかくあなたがしていることのためにIFSは必要ありません。

OLDIFS=$IFS

IFS=$OLDIFS

これにより、IFSが最初に設定された場合にのみ、IFSの古い値が復元されます。 IFSが最初に設定されていなかった場合、これはIFSを完全に異なる空の文字列に設定します。 ksh、bash、またはzshでは、IFSを一時的に設定する必要がある場合は、コードを関数に記述し、IFSをこの関数に対してローカルにすることができます。他のシェルでは、未設定のケースに注意する必要があります。

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

findの出力でコマンド置換を使用しないでください。

  • これは、$IFSの文字で出力を分割します。 IFSを改行に設定すると、出力は改行で分割されますが、改行を含むファイル名は処理できません。
  • コマンド置換の結果が単語に分割されるだけでなく、各単語がグロブパターンとして使用されます。 A[12].pdfA1.pdfA2.pdfと呼ばれるファイルを作成すると、最終的にはA1.pdf A2.pdf A1.pdf A2.pdfになります。 set -fを使用して(そしてset +fを使用して再度)グロブをオフにすることができますが、ここでは(ほとんどの場合)、コマンド置換を使用しないのが正しい方法です。

-exec引数をfindに使用します(または、システムに-print0がある場合は、代わりにfind … -print0 | xargs -0 …を使用できます。これは、複数のファイルを同時に操作する場合にのみ役立ちます-print0はあるが-exec … {} +はない古いLinuxシステムまたは現在のOpenBSDシステムへの移植性が必要です。

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

$fの前後に二重引用符がないことに注意してください(これらが分割の結果であり、その後IFSを変更しておらず、グロビングがオフになっている場合は不要ですが、実際には、それらをオンのままにできない理由がわからない限り、常に二重引用符を付けてください)。

これは不格好で移植性がありません(statはすべてのシステムに存在するわけではなく、その引数は、存在するさまざまなシステム間で異なります)。 touchには、ファイルを別のファイルのタイムスタンプに設定するポータブルオプションがあります:touch -r REFERENCE_FILE FILE。代わりに次の2つの方法のいずれかをお勧めします。

  • 可能であれば、最初に元のファイルを新しいファイルに変換してから、touch -rを呼び出して新しいファイルの日付を設定し、最後に新しいファイルを適切な場所に移動します。入力に何かが起こる前に、出力に問題がないことを確認することをお勧めします。そうしないと、何らかの理由(停電など)で変換が中断された場合、データが失われます。
  • 変換が制御できないブラックボックスである場合、touch -rを2回使用できます。1回は元のファイルの日付を空の一時ファイル(自動的に作成されます)に保存し、次に一時ファイルを使用して日付を復元する変換。

したがって:

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

何らかの理由で、touch -rに関する回答を逃しました。何らかの奇妙な理由で、GNU coreutils 'statが承認された回答のようにないか、touch -rを使用できない場合は、touchフレンドリーな形式で、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

ただし、実際にはtouch -rを使用してください。

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

「映画製作」プロセスから来る同じ問題がありました。

以下の例では、_orig_file.wav_は元のタイムスタンプを持つファイルですが、_processed_file.wav_は同じ内容のファイルですが、タイムスタンプが間違っています。

前:

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

コマンド:

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

後:

_localhost $ ls -lh orig_file.wav processed_file.wav Jul 9 2018 processed_file.wav Jul 9 2018 orig_file.wav_

ノート:

逆ティックのstatは、元のファイルの作成タイムスタンプをUNIXエポック時間(秒単位)で示します。 coreutilsの@は、dateがそれを理解できるように、touchがYYYYMMDDHHmm.SSを使用して再フォーマットできるISO日付に変換します。 dateコマンドを$()に入れました。これは、同じコマンドで再利用できないため、逆ティックに相当します。

0
dominikz