Giữ lại dấu thời gian đã sửa đổi sau khi chỉnh sửa


20

Đối với các tệp trong một thư mục cụ thể, tôi muốn vim không bao giờ chạm vào dấu thời gian "đã sửa đổi".

Bối cảnh là tôi sử dụng Bloxsom để viết blog, sử dụng các tệp văn bản đơn giản ~/bloxsomlàm nguồn của tất cả các bài viết. Ngày bài viết (và do đó thứ tự xuất hiện) được dựa trên ngày sửa đổi của tệp văn bản. Tôi không muốn bài viết bật lên như thể nó mới mỗi khi tôi sửa lỗi đánh máy. (Tôi làm rất nhiều trong số họ ...: D)

Cho đến nay, vim thay đổi dấu thời gian và tem gốc bị mất vĩnh viễn. Điều này là ổn và tôi muốn giữ nó theo cách đó cho hầu hết các tệp trên hệ thống. Nhưng tôi không muốn điều đó cho các tệp blog - tôi luôn có thể touchtệp nếu tôi cần.

Bất kỳ ý tưởng về làm thế nào để điều chỉnh vim vào hành vi này?


2
vim.wikia.com/wiki/ Kẻ - tất nhiên bạn có thể sử dụng các ràng buộc perl thay thế
Ulrich Dangel

Câu trả lời:


22

Tôi không nghĩ vim có tính năng này. Một cách khác là sửa đổi một bản sao và đặt dấu thời gian một cách thích hợp, ví dụ:

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

Hoặc thậm chí tốt hơn:

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

7

Nếu bạn cần vui vẻ:

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

Thay thế đường dẫn bằng đường dẫn tệp thực tế của bạn


5

Tôi đã viết một kịch bản Perl cho điều đó.

Đó là một trình bao bọc xung quanh vim, được lưu ~/bin/vim-nomtime.plvà sử dụng thông qua alias vim='~/bin/vim-nomtime.pl'trong .bashrc của tôi.

#!/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->{$_}, $_;
    }
}

Một số tính năng tốt:

  • hỗ trợ nhiều tên tập tin

  • hỗ trợ nhiều thư mục "đã xem"

  • hỗ trợ dir liên kết

  • có thể được tăng cường với các tiêu chí khác

hầu hết trong số đó có thể cũng đạt được với phiên bản vim thuần túy. Nhược điểm của giải pháp này so với giải pháp thuần túy mong muốn của tôi là:

  • nó chỉ phục hồi tem sau vim đã thoát, vì vậy nếu tôi chỉnh sửa lâu và lưu thường xuyên, tệp biệt thự "bật lên" như mới cho đến khi tôi thoát vim

  • nó hỗ trợ nhiều tệp trên dòng lệnh, nhưng theo một cách khá ngây thơ - nó chỉ kiểm tra xem thứ trên @ARGVlà một tệp. Điều này có lẽ sẽ không hoạt động với các ký tự đại diện (ví dụvim note-*.txt ) hoặc các công cụ hài hước khác

  • đó không phải là bằng chứng sự cố, thậm chí có thể không phải bằng chứng HUP (điều đó có thể được thực hiện)

  • ... Chào mừng, đó là một cái bọc. (Ý tôi là, nếu chúng ta giải quyết mọi thứ thông qua trình bao bọc, chúng ta sẽ có bao nhiêu trình bao bọc trước khi có điều gì đó xấu xảy ra?)


Ngày 3 tháng 5 năm 2019 và tôi vừa sửa đổi một tệp từ ngày 11 tháng 11 năm 2017 và nó có cả sửa đổi của tôi và giữ nguyên dấu thời gian ban đầu. :)
jmort253

1

Tập lệnh ngắn này sẽ duy trì thời gian sửa đổi nếu bất kỳ thư mục gốc nào của tệp chứa .nomtimetệp:

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

Hãy thử bashchức năng này (dựa trên câu trả lời của Shâu Shắc )

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

Bây giờ chúng tôi có thể chỉnh sửa tập tin và duy trì thời gian sửa đổi bằng cách sử dụng này

vi-preserve-time file1.txt file2.txt

(1) Điều này gần giống với câu trả lời của Shâu Shắc từ năm năm trước. (2) Điều này giả định rằng người dùng chỉ gọi vimột tệp duy nhất tại một thời điểm; nó sẽ không làm việc cho vi file1 file2. (3) Không cần phải nói rằng, nếu người dùng chuyển sang một tệp khác :e, nó sẽ không được xử lý.
G-Man nói 'Phục hồi Monica'

Xin lỗi về việc quên tham khảo, bây giờ tôi đã thêm một liên kết tham chiếu đến câu trả lời của Shâu Shắc.
Steely Wing

Về câu hỏi số 3 của bạn, tôi nghĩ rằng nếu bạn mở một tệp khác không nằm trong dòng lệnh thì đó là vấn đề của bạn.
Steely Wing

1
Quan điểm của tôi là, nếu câu hỏi hỏi về Làm thế nào tôi có thể khiến vim hành xử theo cách tôi muốn?, Và bạn cung cấp một chức năng trông giống như nó đang khiến vim hành xử theo cách người dùng muốn, bạn có trách nhiệm ghi lại bất kỳ giới hạn nào của bạn câu trả lời. OK, có thể nhận xét của tôi là một chút không công bằng, đến nỗi tất cả các câu trả lời khác dường như có cùng giới hạn, và không ai trong số họ đề cập đến nó, theo như tôi có thể nói. Tôi chỉ xem lại câu trả lời của bạn vì nó mới; Tôi đã không dành nhiều thời gian để xem các câu trả lời khác.
G-Man nói 'Phục hồi Monica'

1

Có một tùy chọn để sao chép dấu thời gian từ một tệp khác.

touch -m -r file_source file_target

Thí dụ:

[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

Tôi đã tìm thấy một giải pháp tuyệt vời trên trang web này , nó tạo ra một hàm vim để lưu tệp hiện tại trong khi duy trì thời gian sửa đổi hiện có và liên kết chức năng này với F4phím chức năng:

Tuy nhiên, tôi thấy rằng chức năng ban đầu có một lỗi nhỏ, kích hoạt cảnh báo sau nếu F4được sử dụng hai lần trên cùng một tệp, vì vim bị nhầm lẫn khi thời gian sửa đổi thay đổi:

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

May mắn thay, điều này rất dễ khắc phục: Tôi đã thêm lệnh "chỉnh sửa" vào chức năng ban đầu để tải lại tệp sau khi khôi phục dấu thời gian, vì vậy vim biết thời gian sửa đổi để mong đợi tệp có.

Đây là chức năng vim được sửa đổi với sửa lỗi này, có thể được thêm vào ~/.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>

Lưu ý: Chức năng này dựa trên các phiên bản GNU của date, stattouch.


0

Sử dụng một số khái niệm được mô tả ở trên, đây là một bí danh một lớp rất nhanh và bẩn cho CSH, tạo ra lệnh "chỉnh sửa" cho mục đích này:

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

Bạn có thể dễ dàng sử dụng biến môi trường $ VISUAL hoặc $ EDITOR thay cho "vim". Bằng cách này, bạn có thể ban hành lệnh sau để thay đổi trình chỉnh sửa mặc định

setenv VISUAL nano

Bây giờ, bí danh không cần phải được xác định lại để phù hợp với các biên tập viên khác nhau, làm cho nó có phần dễ mang theo hơn. Dĩ nhiên, nếu bạn sử dụng shell khác với CSH hoặc TCSH, các ví dụ trên có thể được điều chỉnh cho phù hợp.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.