Vimでバイナリファイルを編集する方法


77

バイナリファイルを何らかの16進モードで編集する方法はありますか?

たとえば、次のように表示される、xxdまたは次のhexdump -Cようなバイナリデータがある場合:

$ hexdump -C a.bin | head -n 5
00000000  cf fa ed fe 07 00 00 01  03 00 00 80 02 00 00 00  |................|
00000010  12 00 00 00 40 05 00 00  85 00 20 00 00 00 00 00  |....@..... .....|
00000020  19 00 00 00 48 00 00 00  5f 5f 50 41 47 45 5a 45  |....H...__PAGEZE|
00000030  52 4f 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |RO..............|
00000040  00 00 00 00 01 00 00 00  00 00 00 00 00 00 00 00  |................|

$ xxd a.bin | head -n 5
0000000: cffa edfe 0700 0001 0300 0080 0200 0000  ................
0000010: 1200 0000 4005 0000 8500 2000 0000 0000  ....@..... .....
0000020: 1900 0000 4800 0000 5f5f 5041 4745 5a45  ....H...__PAGEZE
0000030: 524f 0000 0000 0000 0000 0000 0000 0000  RO..............
0000040: 0000 0000 0100 0000 0000 0000 0000 0000  ................

特定の位置で値を変更したい場合、この種のビューは、たとえば変更する位置が既知の文字列の近くにある場合など、適切な場所を見つけるのに役立ちます。

回答:


89

最も簡単な方法は、binaryオプションを使用することです。から:help binary

This option should be set before editing a binary file.  You can also
use the -b Vim argument.  When this option is switched on a few
options will be changed (also when it already was on):
        'textwidth'  will be set to 0
        'wrapmargin' will be set to 0
        'modeline'   will be off
        'expandtab'  will be off
Also, 'fileformat' and 'fileformats' options will not be used, the
file is read and written like 'fileformat' was "unix" (a single <NL>
separates lines).
The 'fileencoding' and 'fileencodings' options will not be used, the
file is read without conversion.

[..]

When writing a file the <EOL> for the last line is only written if
there was one in the original file (normally Vim appends an <EOL> to
the last line if there is none; this would make the file longer).  See
the 'endofline' option.

これを行わず、環境がマルチバイトエンコーディング(ほとんどの人が使用するUTF-8など)を使用している場合、Vimはテキストをそのままエンコードしようとし、通常はファイルが破損します。

これを確認するには、ファイルを開き、単にを使用し:wます。現在は変更されています。
あなたが設定した場合LANGLC_ALLするC(ASCII)、Vimは何も変換しないと、ファイルは同じままVimは任意のマルチバイトエンコーディングを行う必要がないので(それはまだかかわらず、改行が追加されます)。

私は個人的にバイナリを無効 set wrapすることを好みますが、他の人はそれを有効にすることを好むかもしれません。YMMV。別の便利なことはです:set display=uhex。から:help 'display'

uhex            Show unprintable characters hexadecimal as <xx>
                instead of using ^C and ~C.

最後のヒントとして、ルーラーのカーソルの下にある文字の16進値を%B:set rulerformat=0x%B)で表示できます。

より高度な: xxd

このxxd(1)ツールを使用してファイルをより読みやすい形式に変換し、(これは重要なビットです)編集した「読みやすい形式」を解析し、バイナリデータとして書き戻すことができます。xxdはの一部でvimあるため、vimインストール済みの場合はにもインストールする必要がありますxxd

使用するには:

$ xxd /bin/ls | vi -

または、既にファイルを開いている場合は、次を使用できます。

:%!xxd

ここで変更を行います。ディスプレイの左側(16進数)でそれを行う必要があり、右側(印刷可能な表現)への変更は書き込み時に無視されます。

保存するには、次を使用しますxxd -r

:%!xxd -r > new-ls

これにより、ファイルがに保存されますnew-ls

または、現在のバッファにバイナリをロードするには:

:%!xxd -r

からxxd(1)

   -r | -revert
          reverse operation: convert (or patch) hexdump into  binary.   If
          not  writing  to stdout, xxd writes into its output file without
          truncating it. Use the combination -r -p to read plain hexadeci‐
          mal dumps without line number information and without a particu‐
          lar column layout. Additional  Whitespace  and  line-breaks  are
          allowed anywhere.

そして、それを使っ:wて書くだけです。(注意binary 上記の概要と同じ理由で、ファイルに書き込む前にオプションを設定する必要があります)。

これを少し簡単にする補完キーバインド:

" Hex read
nmap <Leader>hr :%!xxd<CR> :set filetype=xxd<CR>

" Hex write
nmap <Leader>hw :%!xxd -r<CR> :set binary<CR> :set filetype=<CR>

gVimを使用している場合は、[ツール] H [HEXに変換]および[ツール]➙[元に戻す]でメニューからも使用できます。

Vimのヒントのwikiはより多くの情報といくつかのヘルパースクリプトを持つページがあります。個人的には、バイナリファイルを頻繁に編集している場合は、実際の16進エディターを使用した方が良いと思います。Vimはやる べきことをすることができますが、明らかにそのために設計されたものではあり:set binaryません。


4
素敵な答えですが、おそらく「自宅でこれを試さないでください、子供たち!」
msw

いくつかのバイトを削除する必要がある場合はどうなりますか?たとえば、バイナリの途中。
アントンK

Vimが何をしているのかわかりませんが、何も変更していないにもかかわらず、200KBのバイナリファイルに95KBのテキストが追加されています。でも:set binary noeol fenc=utf-8。実際、それが言う前にファイルを開くとすぐにそれをしてい[noeol] [converted]ます。なぜvimはバッファを150%大きくする必要があるのですか?そのようなファイルが破損しないようにするにはどうすればよいですか?
ブレーデンベスト

動作するのは、読み取り:r !xxd <file>または書き込みのみです(または$ xxd <file> | vim -:w !xxd -r > <file>が、これは理想的ではありません。
ブレーデンベスト

素晴らしい答え。blessのURLは機能しないことに注意してください。私はgithub.com/bwrsandman/Blessの githubでそれを見つけた(と思う)。
ソノファグン

19

バイナリファイルの内容を16進表示で表示するには、ファイルを開き、バイナリモードをオンにして、xxdコマンドでバッファーをフィルター処理します。

:set binary
:%!xxd

左側の領域で変更を行い(16進数を編集)、準備ができたらをフィルターしてxxd -r、最後にファイルを保存します。

:%!xxd -r
:w

開いてから閉じるまでのフィルタリング手順が面倒で、.bin拡張機能付きのファイルでこれを行うことが多い場合は、vimrcにこれを追加してプロセスを自動化できます。

" for hex editing
augroup Binary
  au!
  au BufReadPre  *.bin let &bin=1
  au BufReadPost *.bin if &bin | %!xxd
  au BufReadPost *.bin set ft=xxd | endif
  au BufWritePre *.bin if &bin | %!xxd -r
  au BufWritePre *.bin endif
  au BufWritePost *.bin if &bin | %!xxd
  au BufWritePost *.bin set nomod | endif
augroup END

私はこれらの命令を(バイナリファイルを開く、続く場合は:%!xxd:%!xxd -r:w、didntの変更を加える!)そして、書かれたバイナリファイルはありませんオリジナルと同じ...これは(私がテストしたあなたのためのケースです/bin/ls)。:set binary保存する前に使用する必要があります(理由を説明する答えも参照してください)... vimrcにあるのでしょうか?しかしかかわらず、私は常に使用することになりset binary、安全のために...
マーティンTournoij

1
代わりに追加することaugroupにスクリプトを~/.vim/plugin/binary.vimあなたが乱雑にしたくない場合.vimrc
thom_nic

インストール外国にしている場合は、そのaugroup Binaryリストはに位置しています:help hex-editing:help using-xxd5.5(1999年9月)以降の任意のVimで。
bb010g

6

「bvi」エディターを使用します。 http://bvi.sourceforge.net/ (すべてのLinuxリポジトリにあります。)

$ apt-cache show bvi
[snip]
Description-en: binary file editor
 The bvi is a display-oriented editor for binary files, based on the vi
 text editor. If you are familiar with vi, just start the editor and begin to
 edit! If you never heard about vi, maybe bvi is not the best choice for you.

1
より高度な代替手段は、vimコントロールを備えたbviplusです。
アントンK


3

TL; DR回答

Vimでバイナリモードでファイルを開きます。

vim -b <file_to_edit>

Vimでは、次のように16進編集モードに入ります。

:%!xxd -p

保存する:

:%!xxd -p -r
:w

これにより、バッファが16進モードから変換され、通常のようにファイルが保存されます。

-pオプションに注意してください。これにより、余分な印刷可能およびアドレスの毛羽立ちがすべて回避され、ヘックスが表示されます。追加のコンテキストが必要な場合は、-pを省略します。

バイナリモードではないVimでファイルを開くときは注意してください。保存すると、ファイルの末尾に(通常は意図しない)LF文字が追加されます。


これは、他の回答にないものを実際には追加しません。
ハーブウルフ

5
実際のTL; DRは:h using-xxd現在も使用されており、それ以降はv7.0001おそらくより長く使用されています。ユーザーがドキュメントを検索した場合、このサイトはあまりアクティブではありません。
トミー

1

これは、一時ファイルを使用してジョブを実行する便利な小さなvimプラグインのように見えます。

数年前、似たようなプラグインを見つけて、自分の使用に合わせて改良しました。必要な場合に備えて、関連するコードをここに含めました。これもxxdツールに基づいています。上記でリンクしたGitHubのバージョンはより適切に動作するはずですが、実際に自分で使用したことはないので、確かに動作することがわかっているこのバージョンも投稿すると思いました。

この他のバージョンのソースはvim wikia、特にこのページでした。

コードは次のとおりです。

"-------------------------------------------------------------------------------  
" Hexmode  
"-------------------------------------------------------------------------------  
" Creates an automatic hex viewing mode for vim by converting between hex dump  
" and binary formats. Makes editing binary files a breeze.  
"-------------------------------------------------------------------------------  
" Source: vim.wikia.com/wiki/Improved_Hex_editing  
" Author: Fritzophrenic, Tim Baker  
" Version: 7.1  
"-------------------------------------------------------------------------------  
" Configurable Options {{{1  
"-------------------------------------------------------------------------------  

" Automatically recognized extensions  
let s:hexmode_extensions = "*.bin,*.exe,*.hex"  

"-------------------------------------------------------------------------------
" Commands and Mappings {{{1
"-------------------------------------------------------------------------------

" ex command for toggling hex mode - define mapping if desired
command! -bar Hexmode call ToggleHex()
command! -nargs=0 Hexconfig edit $VIM\vimfiles\plugin\hexmode.vim | exe "normal 11G" | exe "normal zo"

nnoremap <C-H> :Hexmode<CR>
inoremap <C-H> <Esc>:Hexmode<CR>
vnoremap <C-H> :<C-U>Hexmode<CR>

"-------------------------------------------------------------------------------    
" Autocommands {{{1  
"-------------------------------------------------------------------------------  

if exists("loaded_hexmode")  
    finish  
endif  
let loaded_hexmode = 1  

" Automatically enter hex mode and handle file writes properly  
if has("autocmd")  
  " vim -b : edit binary using xxd-format  
  augroup Binary  
    au!  

    " set binary option for all binary files before reading them  
    exe "au! BufReadPre " . s:hexmode_extensions . " setlocal binary"

    " if on a fresh read the buffer variable is already set, it's wrong
    au BufReadPost *
          \ if exists('b:editHex') && b:editHex |
          \   let b:editHex = 0 |
          \ endif

    " convert to hex on startup for binary files automatically
    au BufReadPost *
          \ if &binary | Hexmode | endif

    " When the text is freed, the next time the buffer is made active it will
    " re-read the text and thus not match the correct mode, we will need to
    " convert it again if the buffer is again loaded.
    au BufUnload *
          \ if getbufvar(expand("<afile>"), 'editHex') == 1 |
          \   call setbufvar(expand("<afile>"), 'editHex', 0) |
          \ endif

    " before writing a file when editing in hex mode, convert back to non-hex
    au BufWritePre *
          \ if exists("b:editHex") && b:editHex && &binary |
          \  let oldro=&ro | let &ro=0 |
          \  let oldma=&ma | let &ma=1 |
          \  silent exe "%!xxd -r" |
          \  let &ma=oldma | let &ro=oldro |
          \  unlet oldma | unlet oldro |
          \ endif

    " after writing a binary file, if we're in hex mode, restore hex mode
    au BufWritePost *
          \ if exists("b:editHex") && b:editHex && &binary |
          \  let oldro=&ro | let &ro=0 |
          \  let oldma=&ma | let &ma=1 |
          \  silent exe "%!xxd" |
          \  exe "set nomod" |
          \  let &ma=oldma | let &ro=oldro |
          \  unlet oldma | unlet oldro |
          \ endif
  augroup END  
endif  

"-------------------------------------------------------------------------------
" Functions {{{1
"-------------------------------------------------------------------------------

" helper function to toggle hex mode
function! ToggleHex()
  " hex mode should be considered a read-only operation
  " save values for modified and read-only for restoration later,
  " and clear the read-only flag for now
  let l:modified=&mod
  let l:oldreadonly=&readonly
  let &readonly=0
  let l:oldmodifiable=&modifiable
  let &modifiable=1
  if !exists("b:editHex") || !b:editHex
    " save old options
    let b:oldft=&ft
    let b:oldbin=&bin
    " set new options
    setlocal binary " make sure it overrides any textwidth, etc.
    let &ft="xxd"
    " set status
    let b:editHex=1
    " switch to hex editor
    set sh=C:/cygwin/bin/bash
    %!xxd
  else
    " restore old options
    let &ft=b:oldft
    if !b:oldbin
      setlocal nobinary
    endif
    " set status
    let b:editHex=0
    " return to normal editing
    %!xxd -r
  endif
  " restore values for modified and read only state
  let &mod=l:modified
  let &readonly=l:oldreadonly
  let &modifiable=l:oldmodifiable
endfunction

" vim: ft=vim:fdc=2:fdm=marker
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.