za pomocą statystyki, aby zapewnić znacznik czasu dla dotyku

11

Próbuję OCR niektóre dokumenty insitu (z wiersza polecenia systemu Linux na współużytkowaniu systemu Windows). Proces OCRing znajduje się w find, a ja mętlikami użyłem polecenia find, aby poprawnie poprowadzić pliki przez pętlę.

Jednak muszę zachować oryginalny znacznik czasu dla zmodyfikowanego. Obecnie próbuję użyć statystyk i dotknąć, jak poniżej:

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

Oczywiście polecenie dotykowe kończy się niepowodzeniem. osobne uruchamianie poleceń Zauważyłem, że „stat -c” to coś takiego:

1334758696

który jest jak żadna randka, którą znam. Czuję się, jakbym był blisko, ale nie mogę wymyślić, jak przekonwertować datę, którą mam, na wersję przyjazną dla dotyku. Czy to jakaś sekunda z czegoś?

Tim Alexander
źródło
Poza tym: twoje użycie IFSwydaje się niezwykłe. Czy naprawdę chciałeś podzielić na backspace ( \b)? Zobacz wskazówki na unix.stackexchange.com/questions/9496/ ...
Mikel

Odpowiedzi:

17

stat'swyjście to uniksowy znacznik czasu, zwany także sekundami od epoki .

Wszystkie jądra GNU, które akceptują datę, pozwalają zamiast tego wstawić znacznik czasu, poprzedzając go znacznikiem czasu @.

Więc spróbuj tego

touch -d @$ORIGTS $f

Zobacz coreutils - Sekundy od epoki

Mikel
źródło
ah, co tłumaczy wiele znaczników czasu, które widziałem teraz w Linuksie! Bardzo dziękuję
Tim Alexander
8

touchmoże użyć znacznika czasu pliku za pomocą -ropcji. Możesz chcieć wyprowadzić plik do innego pliku (zakładam, że poniżej -ifjest plik wejściowy i -ofplik wyjściowy)

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
źródło
+1 za unikanie stat.
l0b0
3

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

Ponieważ zakładasz powłokę echo -e, a i tak masz uderzenie w linii shebang, możesz użyć IFS=$'\n\b'. Przekształcanie separatora w backspace jest raczej dziwne. I tak nie potrzebujesz IFStego, co robisz.

OLDIFS=$IFS

IFS=$OLDIFS

Zauważ, że przywraca to starą wartość IFStylko wtedy, gdy IFSzostała początkowo ustawiona. Jeśli IFSpoczątkowo był rozbrojony, ustawia IFSsię na pusty ciąg, który jest zupełnie inny. W ksh, bash lub zsh, jeśli musisz ustawić IFStymczasowo, możesz napisać kod w funkcji i ustawić ją IFSlokalnie. W innych powłokach musisz uważać na nierozbieralną obudowę.

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

Nigdy nie używaj podstawiania poleceń na wyjściu find.

  • Dzieli to wynik na znaki w $IFS. Jeśli ustawisz IFSna nową linię, spowoduje to podział wyniku na nowe linie, ale nadal nie możesz obsługiwać nazw plików zawierających nowe linie.
  • Wynik zastąpienia polecenia jest nie tylko podzielony na słowa, ale następnie każde słowo jest używane jako wzorzec globalny. Jeśli zgłosisz pliki A[12].pdf, A1.pdfa A2.pdfskończysz na A1.pdf A2.pdf A1.pdf A2.pdf. Możesz wyłączyć globowanie za pomocą set -f(i ponownie za pomocą set +f), ale tutaj (jak przez większość czasu) właściwym sposobem nie jest stosowanie zastępowania poleceń.

Użyj -execargumentu, aby find(lub jeśli twój system ma -print0, możesz użyć find … -print0 | xargs -0 …zamiast tego; jest to przydatne tylko do działania na wielu plikach na raz, jeśli potrzebujesz przenośności do starożytnych systemów Linux lub obecnych systemów OpenBSD, które mają, -print0ale nie -exec … {} +).

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

Pamiętaj, że brakuje ci podwójnych cudzysłowów $f(nie są one potrzebne, jeśli są to wyniki podziału i od tego czasu nie zmieniłeś się, IFSa globowanie jest wyłączone, ale tak naprawdę zawsze umieszczaj podwójne cudzysłowy, chyba że wiesz, dlaczego możesz „ zostaw je włączone).

Jest to niezdarne i nieprzenośne ( statnie istnieje we wszystkich systemach, a jego argumenty są różne w różnych systemach, w których istnieje). touchposiada przenośny opcję, aby ustawić pliku do znacznika czasu innego pliku: touch -r REFERENCE_FILE FILE. Zamiast tego poleciłbym jedno z dwóch podejść:

  • Jeśli możesz, najpierw przekształć oryginalny plik w nowy plik, a następnie zadzwoń, touch -raby ustawić datę nowego pliku, a na koniec przenieś nowy plik na miejsce. Lepiej jest upewnić się, że wyjście jest w porządku, zanim cokolwiek stanie się z danymi wejściowymi; w przeciwnym razie, jeśli transformacja zostanie przerwana z jakiegokolwiek powodu (np. awaria zasilania), utracisz dane.
  • Jeśli transformacja jest czarną skrzynką, nad którą nie masz kontroli, możesz użyć jej touch -rdwukrotnie: raz, aby zapisać datę oryginalnego pliku w pustym pliku tymczasowym (który zostanie utworzony automatycznie), a następnie ponownie po transformacji, aby przywrócić datę za pomocą pliku tymczasowego.

A zatem:

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- przestań być zły”
źródło
0

Z jakiegoś powodu przegapiłem odpowiedź na temat touch -r; jeśli z jakiegoś dziwnego powodu nie masz GNU coreutils ' statjak w zaakceptowanej odpowiedzi ani nie możesz użyć touch -r, oto jak uzyskać znacznik czasu w touchformacie przyjaznym dla 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

Ale tak naprawdę po prostu użyj touch -r:

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

Miałem ten sam problem, pochodzący z procesu tworzenia filmów.

W poniższym przykładzie orig_file.wavjest plik z oryginalnym znacznikiem czasu, podczas processed_file.wavgdy plik o tej samej zawartości, ale niepoprawnym znaczniku czasu.

PRZED:

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

KOMENDA:

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

PO:

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

UWAGI:

statw odwróconych paskach daje znacznik czasu utworzenia oryginalnego pliku jako czas epoki uniksowej (w sekundach). @ Z coreutils konwertuje go na datę ISO, która datemoże zrozumieć i sformatować za pomocą YYYYMMDDHHmm.SS, aby to touchzrozumieć. Umieszczam datepolecenie w $ (), jako odpowiednik odwróconych tyknięć, ponieważ nie można ich ponownie użyć w tym samym poleceniu.

dominikz
źródło
(1) Wydaje się, że jest to prawie dokładnie to samo, co odpowiedź Mikołaja Rileya, ale bardziej skomplikowane. Dlaczego ktoś miałby chcesz korzystać z tego, że zamiast (lub, jeszcze lepiej, odpowiedź Glenn Jackmana , używając touch -r)? (2)  stat można umieścić $(…); można ich używać wiele razy w jednym poleceniu.
G-Man mówi „Przywróć Monikę”
Wygląda na to, że oprócz odpowiedzi, która używa czasu modyfikacji zamiast tworzyć czas, masz rację. Nie zauważyłem tej drugiej odpowiedzi. Możesz obniżyć głos mój.
dominikz
Cóż, jeśli mnie o to poprosisz, to nie jest zabawne. :-) ⁠
G-Man mówi „Przywróć Monikę”