はじめに
Linuxでファイルの整合性を確認する際、ls -l でサイズや更新日時を確認し、別途 md5sum でハッシュ値を確認するのが面倒だと感じたことはありませんか?
「ls -l のリスト表示の左側に、MD5ハッシュ値が並んでいたら便利なのに……」
そう思い立ち、ls コマンドの結果と md5sum コマンドの結果を合体させた「md5ls」というシェル関数を作成しました。
意外と泥臭い調整(表示ズレ、ディレクトリ判定、隠しファイル対応など)が必要だったので、その完成形を共有します。
完成した「md5ls」コマンド
以下のコードを ~/.bashrc に追記することで使用できます。
md5ls() {
# サブシェル (...) を使うことで、cd しても元の場所には影響を与えない
(
target_dir=""
opts=() # オプション用配列
# 引数解析: ディレクトリとそれ以外(オプション)に分ける
for arg in "$@"; do
if [ -d "$arg" ]; then
target_dir="$arg"
else
opts+=("$arg")
fi
done
# ディレクトリ指定があった場合はそこに移動
# (移動しないと隠しファイルや別ディレクトリのファイルを正しくmd5sumできないため)
if [ -n "$target_dir" ]; then
cd "$target_dir" || return
fi
# --- コマンド生成 ---
# 配列が空の場合に "" を渡さないように分岐する
if [ ${#opts[@]} -eq 0 ]; then
# --group-directories-first でディレクトリを先にまとめて表示
ls_cmd="ls -al --group-directories-first"
else
# オプションがある場合のみ展開して渡す
ls_cmd="ls -al --group-directories-first \"${opts[@]}\""
fi
# ls の実行と md5sum の計算
# LANG=C を指定して日付フォーマットとエラーメッセージを英語に統一
eval "LANG=C $ls_cmd" | awk '
NR==1 { print; next }
{
# --- ファイル名の抽出 ---
# 9列目以降を全て結合してファイル名とする(スペース入りファイル名対応)
fn=""
for(i=9;i<=NF;i++) fn = fn (i==9?"":" ") $i
# --- md5sum の実行 ---
# ファイル名のエスケープ処理(ダブルクォート対策)
safe_fn = fn
gsub(/"/, "\\\"", safe_fn)
# エラー出力(2>&1)も標準出力として受け取る
# ここでも LANG=C を指定して "Is a directory" を確実に検出する
cmd = "LANG=C md5sum \"" safe_fn "\" 2>&1"
if ((cmd | getline line) > 0) {
# ディレクトリの場合は固定メッセージを表示してレイアウト崩れを防ぐ
if (line ~ /Is a directory/) {
result_str = "md5sum: Is a directory"
} else {
# 正常な場合はハッシュ値(空白区切りの先頭)のみ抽出
split(line, arr, " ")
result_str = arr[1]
# 万が一エラー文字列だけが返ってきた場合の対策
if (result_str == "md5sum:") result_str = "Error"
}
} else {
result_str = "Error"
}
close(cmd)
# --- 表示 ---
# %-34s で34文字分の幅を確保して左詰めにする
printf "%-34s %s\n", result_str, $0
}'
)
}
設定を反映させます。
source ~/.bashrc
実行結果
コマンド md5ls を実行すると、左側にMD5ハッシュ、右側に ls -al の結果が表示されます。
$ md5ls
total 1904
md5sum: Is a directory drwxr-xr-x 2 user01 user01 4096 Feb 16 18:59 .
md5sum: Is a directory drwxr-xr-x 13 user01 user01 4096 Feb 16 18:38 ..
0f4e36e42809603f5115b381ed98e250 -rwxr-xr-x 1 user01 user01 577 Feb 16 18:37 buff-cache.sh
b07e4809d2188a128a8329385c59353b -rwxr-xr-x 1 user01 user01 1045 Feb 16 18:37 capture.sh
f7a0fbeb7a3b6cd9af998aeb6dbd82c7 -rwxr-xr-x 1 user01 user01 1028 Feb 16 18:37 demand-paging.py
...
ディレクトリを指定しても動作します(隠しファイルも対応)。
$ md5ls ~/
total 148
md5sum: Is a directory drwxr-x--- 19 user01 user01 4096 Feb 18 11:52 .
md5sum: Is a directory drwxr-xr-x 3 root root 4096 Feb 15 16:43 ..
b9a556fd432880e5ad928f41f42f2608 -rw------- 1 user01 user01 17025 Feb 17 22:32 .bash_history
...
こだわったポイント・技術的な解説
1. ディレクトリの表示崩れ対策
単純に md5sum をディレクトリに対して実行すると、エラーメッセージにディレクトリ名が含まれてしまい、リストの列がガタガタにずれてしまいます。
-
対策:
md5sumの結果に "Is a directory" が含まれる場合は、強制的に"md5sum: Is a directory"という固定長の文字列に置き換えました。 -
工夫:
LANG=Cを付与することで、日本語環境でも確実に "Is a directory" という英語メッセージが出力されるようにしています。
2. --group-directories-first の採用
ハッシュ値が表示される「ファイル」と、エラーメッセージが表示される「ディレクトリ」が混ざると見づらいため、ls に --group-directories-first オプションを追加しました。これにより、ディレクトリが上部にまとまり、視認性が向上しました。
3. 別ディレクトリの隠しファイル対応
md5ls ~/ のようにパスを指定した際、単純に ls の結果を md5sum に渡すと「ファイルが見つからない」というエラーになります(ls はファイル名だけを返すため)。
-
対策: サブシェル
( ... )内で一時的にターゲットディレクトリへcdしてから処理を行うようにしました。これにより、相対パスの問題を解決しつつ、ユーザーのカレントディレクトリには影響を与えません。
4. レイアウトの整形
awk の printf "%-34s %s\n" を使用しています。MD5ハッシュ値は32文字なので、スペース2文字分を加えて34文字幅で左詰めすることで、右側の ls の結果がきれいに縦に並ぶようにしています。
おわりに
既存の md5deep などのツールもありますが、「いつもの ls -l の見た目のままハッシュを知りたい」というニッチな要望を叶えるには、シェル関数を自作するのが一番でした。
普段の作業で、ファイルの整合性をサッと確認したい時に役立てば幸いです。