概要
小ネタ。知ってるともしかしたらイザというときに便利かもしれません。
今はネットワークもストレージも大容量になったので多少大きなファイルを送受信してもあまり困ることはないかもしれません。
一昔前は、回線がとても細い現場とかが多かった記憶。
そういうときに、例えば調査用にログファイルを実機から採取したいって思っても、ファイルサイズがとても大きいクソログファイルとかがあったりするとちょっと困ります。
そんなときに以下のように分割してしまって、必要な分のみを取得したりすると時間も節約できたりするかもしれません。
Linuxでのデータファイルの分割には主に dd コマンドくんが活躍してくれます。
コツは、分割する際に dd コマンドに対して
- conv=noerror を指定する
- skipオプションを指定する
ですね。分割サイズによっては最後の分割ファイルは途中でデータが終わってしまう可能性があります。
その場合でもエラーにせずにデータを最後まで書ききってもらうのに conv=noerror を指定します。
サンプル
#!/usr/bin/env bash # # ddコマンドを使ってデータを任意のサイズに分割 # # REFERENCES: # - https://www.gnu.org/software/gawk/manual/gawk.html # - https://www.gnu.org/software/gawk/manual/gawk.html#Printf-Examples # - https://www.gnu.org/software/coreutils/manual/html_node/sort-invocation.html # - https://www.gnu.org/software/coreutils/manual/html_node/dd-invocation.html#dd-invocation # basedirpath=/tmp/try-linux/split/using_dd rm -rf "${basedirpath}" mkdir -p "${basedirpath}" ## テスト用のファイルを生成 # # 500KBのファイル dd if=/dev/zero of="${basedirpath}/zero.bin" bs=1024 count=500 2>/dev/null ## 生成したファイルのサイズを保持(分割時に利用する) # _size=$(ls -l "${basedirpath}/zero.bin" | awk '{print $5}') echo "FileSize: ${_size}" ## 30KBずつで分割 # _srcfile="${basedirpath}/zero.bin" _chunk=$(( 1024 * 30 )) _total=0 _count=0 while [ "${_total}" -lt "${_size}" ] do (( _count++ )) # きっちり分割できない場合でもエラーにならずに入力ファイルの最後まで # 書き出してもらうために conv=noerror オプションを付与 # # また、skip オプションを指定しているので、必要なメモリ容量は一定となるようにしている dd \ conv=noerror \ if="${_srcfile}" \ of="${_srcfile}.${_count}" \ bs="${_chunk}" \ skip="$(( _count - 1 ))" \ count=1 \ 2>/dev/null _total=$(( _total + _chunk )) done echo "Split: ${_count} files" ## 確認 # # - ls -l の先頭行は total xxxx という表示になるので除外 (awk '{if (NR>1) printf "%6d %s\n",$5,$9}') # - 分割数が10個以上になると、そのままだと数字順に並ばないのでソート (sort -n -t . -k 3) # - -n : --numeric-sort (数値でソート) # - -t : --field-separator (指定した文字をセパレータとして利用) # - -k : --key (ソート対象とするカラム位置) # ls -l "${basedirpath}" \ | awk '{if (NR>1) printf "%6d %s\n",$5,$9}' \ | sort -n -t . -k 3 echo '----------------------------------------------------' ## 復元 # cat $(ls ${basedirpath}/zero.bin.* | sort -n -t . -k 3) > "${basedirpath}/zero.bin.restore" ls -l "${basedirpath}"/{zero.bin,zero.bin.restore} echo '----------------------------------------------------' ## 復元確認 # diff -s "${basedirpath}"/{zero.bin,zero.bin.restore}
try-linux/using_dd.sh at master · devlights/try-linux · GitHub
実行すると以下のようになります。
gitpod /workspace/try-linux $ make ENTER EXAMPLE NAME: split_u [INPUT ] split_u [TARGET] split_using_dd [SCRIPT] basic/split/using_dd.sh ===== START [basic/split/using_dd.sh] ===== FileSize: 512000 Split: 17 files 512000 zero.bin 30720 zero.bin.1 30720 zero.bin.2 30720 zero.bin.3 30720 zero.bin.4 30720 zero.bin.5 30720 zero.bin.6 30720 zero.bin.7 30720 zero.bin.8 30720 zero.bin.9 30720 zero.bin.10 30720 zero.bin.11 30720 zero.bin.12 30720 zero.bin.13 30720 zero.bin.14 30720 zero.bin.15 30720 zero.bin.16 20480 zero.bin.17 ---------------------------------------------------- -rw-r--r-- 1 gitpod gitpod 512000 Feb 1 08:51 /tmp/try-linux/split/using_dd/zero.bin -rw-r--r-- 1 gitpod gitpod 512000 Feb 1 08:51 /tmp/try-linux/split/using_dd/zero.bin.restore ---------------------------------------------------- Files /tmp/try-linux/split/using_dd/zero.bin and /tmp/try-linux/split/using_dd/zero.bin.restore are identical ===== END [basic/split/using_dd.sh] ===== DONE
参考情報

LinuxサーバHacks―プロが使うテクニック&ツール100選
- 作者:ロブ フリッケンガー
- 発売日: 2003/11/01
- メディア: 単行本
過去の記事については、以下のページからご参照下さい。
- いろいろ備忘録日記まとめ
サンプルコードは、以下の場所で公開しています。
- いろいろ備忘録日記サンプルソース置き場