Conserva il timestamp modificato dopo la modifica


20

Per i file all'interno di una cartella specifica, vorrei che vim non toccasse mai il timestamp "modificato".

Lo sfondo è che uso Bloxsom per i blog, che utilizza file di testo normale ~/bloxsomcome fonte di tutti gli articoli. La data dell'articolo (e quindi l'ordine di apparizione) si basa sulla data di modifica del file di testo. Non voglio che l'articolo compaia come se fosse nuovo ogni volta che aggiusto un refuso. (Ne faccio molti ...: D)

Finora, Vim modifica il timestamp e il timbro originale viene perso per sempre. Questo va bene e voglio mantenerlo così per la maggior parte dei file sul sistema. Ma non lo voglio per i file del blog - posso sempre touchil file se ne ho bisogno.

Qualche idea su come modificare Vim in questo comportamento?


2
vim.wikia.com/wiki/… - puoi ovviamente usare invece i collegamenti perl
Ulrich Dangel,

Risposte:


22

Non credo che Vim abbia questa funzione. Un'alternativa è modificare una copia e impostare il timestamp in modo appropriato, ad esempio:

cp -p post temp
vim temp
touch -r post temp
cp -p temp post

O ancora meglio:

touch -r post timestamp
vim post
touch -r timestamp post

7

Se hai bisogno di divertirti:

file=path; mtime=$(stat -c %y "$file"); vi "$file"; touch -d "$mtime" "$file"

Sostituisci percorso con il tuo percorso file effettivo


5

Ho scritto una sceneggiatura Perl per questo.

È un wrapper per vim, salvato ~/bin/vim-nomtime.ple messo in uso tramite alias vim='~/bin/vim-nomtime.pl'nel mio .bashrc.

#!/usr/bin/perl
use strict;
use warnings;
use Cwd qw/ abs_path /;

my @dirs = qw( ~/blosxom /srv/relief/blosxom );

s/^~/$ENV{HOME}/ foreach @dirs;

# do we want to preserve stamp on this file?
sub fits {
    my $dir = abs_path($_[0]);
    my $fits = 0;
    foreach (@dirs) {
        my $preserved_dir = abs_path($_);
        $fits++ if $dir =~ m|^$preserved_dir|;
    }
    return $fits != 0;
}

# store original stamps
my $original_stamp;
foreach (@ARGV) {
    if ( -f $_ and fits($_) ) {
        $original_stamp->{$_} = (stat($_))[9];
    }
}

# run vim as you would
my $cmd = join ' ', 'vim', @ARGV;  
system($cmd) == 0
    or die "vim failed: $!";

# restore stamps if they have changed
foreach (keys %$original_stamp) {
    next unless -f $_;
    my $current_stamp = (stat($_))[9];
    unless ($current_stamp == $original_stamp->{$_}) {
        utime $original_stamp->{$_}, $original_stamp->{$_}, $_;
    }
}

Alcune buone caratteristiche:

  • supporta più nomi di file

  • supporta più dir "guardati"

  • supporta dir simbolizzato

  • può essere migliorato con altri criteri

la maggior parte dei quali potrebbe essere probabilmente ottenuta anche con la versione vim pura. Gli svantaggi di questa soluzione rispetto alla mia soluzione pure-vim desiderata sono:

  • ripristina il timbro solo dopo la chiusura di vim, quindi se eseguo una lunga modifica e salvo regolarmente, il file vill "pop-up" come nuovo fino a quando non esco da vim

  • supporta più file dalla riga di comando, ma in modo abbastanza ingenuo: controlla solo se l'oggetto @ARGVè un file. Questo probabilmente non funzionerebbe con i caratteri jolly (ad esempio vim note-*.txt) o altre cose divertenti

  • non è a prova di crash, probabilmente nemmeno a prova di HUP (che potrebbe essere fatto)

  • ... wel, è un involucro. (Voglio dire, se risolvessimo tutto tramite wrapper, quanti wrapper avremmo prima che accadesse qualcosa di brutto?)


Il 3 maggio 2019 e ho appena modificato un file dall'11 novembre 2017 e ha sia la mia modifica sia il timestamp originale. :)
jmort253,

1

Questo breve script conserverà il tempo modificato se una qualsiasi directory principale del file contiene un .nomtimefile:

#!/bin/bash

dir="${1%/*}"
[ "$dir" = "$1" ] && dir=.
dir=$( readlink -f "$dir" )

nomtime=
while [ -n "$dir" ]; do
    if [ -f "$dir/.nomtime" ]; then
        nomtime=1
        break
    fi
    dir="${dir%/*}"
done

if [ "$nomtime" = 1 ]; then
    T=`tempfile`
    touch -r "$1" $T
fi

vi "$1"

if [ "$nomtime" = 1 ]; then
    touch -r $T "$1"
    rm $T
fi

1

Prova questa bashfunzione (basato sulla risposta di Shâu Shắc )

vi-preserve-time () {
    for file in "$@"; do
        local mtime=$(stat -c %y "$file")
        vi "$file"
        touch -d "$mtime" "$file"
    done
}

Ora possiamo modificare il file e conservare il tempo modificato usando questo

vi-preserve-time file1.txt file2.txt

(1) Questo è quasi identico alla risposta di Shâu Shắc di cinque anni fa. (2) Ciò presuppone che l'utente invochi visolo un singolo file alla volta; non funzionerà per vi file1 file2. (3) Va da sé che, se l'utente passa a un altro file :e, non verrà gestito.
G-Man dice "Ripristina Monica" il

Mi dispiace dimenticare di fare riferimento, ora ho aggiunto un link di riferimento alla risposta di Shâu Shắc.
Steely Wing,

A proposito della tua domanda n. 3, penso che se apri un altro file non si trova nella riga di comando, è un tuo problema.
Steely Wing,

1
Il mio punto è, se la domanda si pone "Come posso fare in modo che vim si comporti come voglio?", E tu fornisci una funzione che sembra far sì che vim si comporti come vuole l'utente, è tua responsabilità documentare eventuali limiti del tuo risposta. OK, forse il mio commento è un po 'ingiusto, in quanto tutte le altre risposte sembrano avere lo stesso limite, e nessuno di loro lo menziona, per quanto posso dire. Stavo solo rivedendo la tua risposta perché era nuova; Non ho trascorso molto tempo a guardare le altre risposte.
G-Man dice "Ripristina Monica" il

1

C'è un'opzione per copiare un timestamp da un altro file.

touch -m -r file_source file_target

Esempio:

[oracle@es abc]$ ls -tlr
total 4
-rw-r--r--. 1 oracle oinstall 102 May  8 20:35 aa.txt
[oracle@es abc]$ echo "hi hi" > b
[oracle@es abc]$ ls -ltr
total 4
-rw-r--r--. 1 oracle oinstall 102 May  8 20:35 aa.txt
-rw-r--r--. 1 oracle oinstall   6 May 13 18:58 b
[oracle@es abc]$ touch -m -r aa.txt b
[oracle@es abc]$ ls -tlr
total 8
-rw-r--r--. 1 oracle oinstall   6 May  8 20:35 b
-rw-r--r--. 1 oracle oinstall 102 May  8 20:35 aa.txt
[oracle@es abc]$ cat b
hi hi

1

Ho trovato un'ottima soluzione in questa pagina Web , che crea una funzione vim per salvare il file corrente preservando il tempo di modifica esistente e associa questa funzione al F4tasto funzione:

Tuttavia, ho scoperto che la funzione originale contiene un bug minore, che attiva il seguente avviso se F4viene utilizzato due volte sullo stesso file, perché vim viene confuso quando cambia il tempo di modifica:

WARNING: The file has been changed since reading it!!!
Do you really want to write to it (y/n)?

Fortunatamente, questo è facile da risolvere: ho aggiunto un comando "modifica" alla funzione originale per ricaricare il file dopo aver ripristinato il timestamp, quindi vim sa che tempo di modifica aspettarsi che il file abbia.

Ecco la funzione vim modificata con questa correzione di bug, che può essere aggiunta a ~/.vimrc:

function! WriteSmall()
    let mtime = system("date -d @`stat -c %Y ".shellescape(expand('%:p')) . "`")
    write
    call system("touch --date='".mtime."' ".shellescape(expand('%:p')))
    edit
endfunction
map <F4> :call WriteSmall()<CR>

Nota: Questa funzione si basa su versioni GNU di date, state touch.


0

Utilizzando alcuni dei concetti sopra descritti, ecco un alias one-liner molto rapido e sporco per CSH che rende disponibile un comando "modifica" per questo scopo:

alias edit 'touch -r \!:1 /tmp/~mtime ; vim \!:1 ; touch -r /tmp/~mtime \!:1 ; rm /tmp/~mtime'

È possibile utilizzare facilmente la variabile di ambiente $ VISUAL o $ EDITOR al posto di "vim". In questo modo è possibile emettere il seguente comando per modificare gli editor predefiniti

setenv VISUAL nano

Ora l'alias stesso non ha bisogno di essere ridefinito per adattarsi a diversi editor, rendendolo un po 'più portatile. Se usi una shell diversa da CSH o TCSH, ovviamente, gli esempi sopra possono essere adattati di conseguenza.

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.