В комментарии Вы спросили следующее:
Существует ли способ сделать это циклом только через файлы, которые были в той области (не, каждый файл в настоящее время открывается)?
Я не думаю, что Vim отслеживает все буферы, к которым ранее получило доступ окно (“область”). Однако Vim является scriptable …
Вот реализация, которая обеспечивает версию этой функциональности при помощи автокоманд для записи (в локальной переменной окна), которым были буферы, активируются в окне.
(Сокращенные) команды:
:Hb
Перечислите исторические буферы для этого окна.:Hbn[!] [N]
Переключитесь на Энный следующий исторический буфер.:bn
, но ограниченный “историческими” буферами текущего окна):Hbp[!] [N]
Переключитесь на Энный предыдущий исторический буфер.:bp
, но ограниченный “историческими” буферами текущего окна):Hbf [N]
(“забудьте”) Удаляют текущий буфер (или буферизуйте номер N) из списка текущего окна исторических буферов.Следующий код мог быть помещен в Ваш .vimrc
или в отдельном файле (например. plugin/buffer-history/buffer-history.vim
где-нибудь под одним из Вашего runtimepath
каталоги):
augroup UL17179_BufferHistory
autocmd!
autocmd BufEnter * call s:RecordBufEnter(0)
" Grab WinEnter, since BufEnter is not triggered when doing
" a bare ':split'. This also means that 'forgetting' a buffer is
" only effective if you switch to another buffer before
" switching away from the window.
autocmd WinEnter * call s:RecordBufEnter(1)
augroup END
function! s:EnsureBufferHistory()
if ! exists('w:BufferHistory')
let w:BufferHistory = []
endif
return w:BufferHistory
endfunction
function! s:RecordBufEnter(w)
let l = s:EnsureBufferHistory()
let b = winbufnr(0)
let i = index(l, b)
if i >= 0
unlet l[i]
endif
let l += [b]
redraw
endfunction
function! s:ForgetBuffer(...)
let l = s:EnsureBufferHistory()
for b in a:000
let b = b ? b+0 : winbufnr(0)
let i = index(l, b)
if i >= 0
call remove(l, i)
else
try
echohl WarningMsg
echomsg 'Buffer' b 'not in history list.'
finally
echohl None
endtry
endif
endfor
endfunction
function! s:ShowBuffers()
let l = s:EnsureBufferHistory()
for b in l
echomsg b bufname(b)
endfor
endfunction
function! s:HistoricalBufferNr(...)
let direction = a:0 >= 1 && !a:1 ? -1 : 1
let move_count = a:0 >= 2 ? max([1, a:2]) : 1
let current_bn = winbufnr(0)
let historical_buffers = copy(filter(s:EnsureBufferHistory(),
\ 'bufexists(v:val)'))
let i = index(historical_buffers, current_bn)
if i < 0
let other_historical_buffers = historical_buffers
elseif i == 0
let other_historical_buffers = historical_buffers[1:]
else
let other_historical_buffers = historical_buffers[i+1:] +
\ historical_buffers[:i-1]
endif
if len(other_historical_buffers) <= 0
try
echohl ErrorMsg
echomsg 'This window has no historical buffers!'
finally
echohl None
endtry
return 0
endif
if direction > 0
let i = (move_count - 1) % len(other_historical_buffers)
else
let l = len(other_historical_buffers)
let i = ((l - 1) * move_count ) % l
endif
return other_historical_buffers[i]
endfunction
" If the 1) user does not give a bang and
" 2) we run 'buffer N' (no bang) from inside the function and
" 3) switching away from the buffer would require a bang,
" then the user will see an ugly 'Error detected while processing
" function' prefix before the usual E37 error message. Hoisting the
" 'buffer N' into the user-defined command means the user will
" just see a normal E37 message.
command! -nargs=0 -count=1 -bang -bar
\ HistoricalBufferNext
\ let s:new_bn = s:HistoricalBufferNr(1, )
\ | if s:new_bn | exe 'buffer' s:new_bn | endif
command! -nargs=0 -count=1 -bang -bar
\ Hbn
\ HistoricalBufferNext
command! -nargs=0 -count=1 -bang -bar
\ HistoricalBufferPrev
\ let s:new_bn = s:HistoricalBufferNr(0, )
\ | if s:new_bn | exe 'buffer' s:new_bn | endif
command! -nargs=0 -count=1 -bang -bar
\ Hbp
\ HistoricalBufferPrev
command! -nargs=* -count=0 -bar
\ HistoricalBufferForget
\ call s:ForgetBuffer(, )
command! -nargs=* -count=0 -bar
\ Hbf
\ HistoricalBufferForget
command! -nargs=0 -bar
\ HistoricalBuffers
\ call s:ShowBuffers()
command! -nargs=0 -bar
\ Hb
\ HistoricalBuffers
Эта команда переименует все файлы к md5sum их содержания. Это означает, что файлы с тем же содержанием получат то же имя.
for f in *; do mv $f $(md5sum $f | cut -d " " -f 1); done
Можно заменить md5sum
с sha1sum
в команде.
Для этой демонстрации я добавил -v
кому: mv
таким образом, мы видим то, что переименовывается.
$ echo 1 > a
$ echo 2 > b
$ echo 1 > c
$ ls -1
a
b
c
$ for f in *; do mv -v $f $(md5sum $f | cut -d " " -f 1); done
`a' -> `b026324c6904b2a9cb4b88d6d61c81d1'
`b' -> `26ab0db90d72e28ad0ba1e22ee510510'
`c' -> `b026324c6904b2a9cb4b88d6d61c81d1'
$ ls -1
26ab0db90d72e28ad0ba1e22ee510510
b026324c6904b2a9cb4b88d6d61c81d1
Можно также безопасно выполнить эту команду в каталоге, где некоторые файлы объединили имя файла, в то время как другой не имеют.
$ echo 1 > d
$ echo 2 > e
$ ls -1
26ab0db90d72e28ad0ba1e22ee510510
b026324c6904b2a9cb4b88d6d61c81d1
d
e
$ for f in *; do mv -v $f $(md5sum $f | cut -d " " -f 1); done
mv: `26ab0db90d72e28ad0ba1e22ee510510' and `26ab0db90d72e28ad0ba1e22ee510510' are the same file
mv: `b026324c6904b2a9cb4b88d6d61c81d1' and `b026324c6904b2a9cb4b88d6d61c81d1' are the same file
`d' -> `b026324c6904b2a9cb4b88d6d61c81d1'
`e' -> `26ab0db90d72e28ad0ba1e22ee510510'
$ ls -1
26ab0db90d72e28ad0ba1e22ee510510
b026324c6904b2a9cb4b88d6d61c81d1
Обратите внимание, что это все еще вычислит хеш файлов, которые уже хешируются. Таким образом, если файлы огромны, Вы могли бы хотеть предотвратить перефразирование.
Это rename-hash
сценарий я использую для переименования файлов к их hashsum, сохраняя расширение неизменным. Берет список файлов, которые будут переименованы как параметры. Использовать -n
как первый параметр для пробного прогона.
#!/bin/sh
unset DRY
[ "$1" == "-n" ] && { DRY=1; shift; }
for i in $@; do
if [ -f "$i" ]; then
HASHSUM=$(md5sum "$i" | sed 's/\(..........\).*/\1/')
DIR=$(dirname "$i")
BASE=$(basename "$i")
EXT=$(echo "$BASE" | sed -n 's/[^.]*\(\..*\)/\1/p')
TARGET="$DIR"/"$HASHSUM""$EXT"
if [ "$TARGET" != "$DIR/$BASE" ]; then
if [ -n "$DRY" ]; then
echo will rename "$i" to "$TARGET"
else
mv "$i" "$TARGET"
fi
fi
fi
done
Пример:
$ rename-hash -n *
will rename test.pdf to ./f604d0d6ad.pdf
will rename images.tar.gz to ./d41d8cd91b.tar.gz
Существуют некоторые утилиты для нахождения дубликатов. Можно использовать, находят и md5sum, но может довольно требоваться много времени.
Я обычно использую fdupes для этого. Если может найти все дубликаты и произвести их имена к stdout. После этого можно проанализировать вывод и переименовать все файлы, как Вы хотите или даже удаляете их.